简体   繁体   中英

Giving a __stdcall function pointer more arguments than it expects

I'm importing circa 1500 functions from a vendor provided dll (all __stdcall). For tedious reasons the dll exists in a number of versions containing various subsets of the full function list (although all functions that do exist have common interface). All of the functions return a UINT indicating an error code, but take various numbers of arguments of diverse types. Currently if GetProcAddress fails (because the function in question doesn't exist in the particular dll version), the function pointer is left = nullptr, which needs to be checked for each time the client calls a function from the dll. I would like instead to assign a pointer to a function which returns a UINT of an appropriate error code. The proposed solution was along these lines:

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);

This approach works as written (despite being explicitly undefined by the standard) but fails as soon as the calls are __stdcall (presumably because we've messed up the stack). I had a look at using (/abusing) bind, but doesn't appear to help with what I'm trying to do (unless I'm missing something). Many of the library function calls end up in a deeply nested loop, so I don't want to incur any (non trivial) overhead in cases where GetProcAddress was able to find the function.

Is there a "correct", standard compliant, way of achieving this behaviour which will work with the __stdcall calling convention, or am I going to have to generate 1500 different versions of missing_func() with varying argument lists, all returning the same value?

You need one dummy function for each stack frame size, since the ret instruction for this convention adjusts the stack pointer correspondingly.

Note that there is a standard error code for "not implemented", I think symbolic name like E_NOTIMPL or such. Check it out.

Creating a wrapper that checks for nullptr before dispatching the call to the imported function seems to work.

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;
};

Here's a demo of how you'd use it. As you can see, it gracefully returns an error code if the wrapper was initialized with nullptr . I tested the same code on VS2013 and it returned the same result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM