简体   繁体   中英

How to create a C++ macro to define function that uses argument list that calls another function?

As bizarre as the title seems, what I want to do is fairly simple. Look at these definitions:

ImportFunc(void, il2cpp_init_utf16, (const Il2CppChar* domain_name));
ImportFunc(void, il2cpp_shutdown, ());
ImportFunc(void, il2cpp_set_config_dir, (const char* config_path));
ImportFunc(void, il2cpp_set_data_dir, (const char* data_path));
ImportFunc(void, il2cpp_set_commandline_arguments, (int argc, const char* const argv[], const char* basedir));
ImportFunc(void, il2cpp_set_commandline_arguments_utf16, (int argc, const Il2CppChar* const argv[], const char* basedir));
ImportFunc(void, il2cpp_set_config_utf16, (const Il2CppChar* executablePath));
ImportFunc(void, il2cpp_set_config, (const char* executablePath));

I have a bunch of these definitions and I want to "turn them into a function". I have tried something like this:

#define ImportFunc(t, n, a) \
t n a \
{ \
void* pfunc = (void*)CallSystem(kernel32, GetProcAddress, Globals::GameAssembly, n); \
return SpoofCall<type>((void*)pfunc, args...); \
}

The issue is how to parse the function arguments and pass them to another function. The SpoofCall function does look like this:

template<typename Ret = void, typename First = void*, typename Second = void*, typename Third = void*, typename Fourth = void*, typename... Stack>
    __forceinline Ret SpoofCall(void* Func, First a1 = First{}, Second a2 = Second{}, Third a3 = Third{}, Fourth a4 = Fourth{}, Stack... args) {

Is there even a way to do it? I can define the function to accept a template and then just call the SpoofCall with these arguments, but I would like to have the function defined with the arguments so I can use them more easily and to integrate them with IntelliSense:

截屏

EDIT: Changed typo in macro

You can try something like:

#define ImportFunc(_type,_name,...) \
        _type (&x_##_name) (__VA_ARGS__) = *ImportT<_type,## __VA_ARGS__>(#_name)

// Convenience typedef, as spelling template function
// returning template pointer to function
// is *too* error-prone otherwise
template <typename Ret, typename ...Args>
using FuncT = Ret (Args...);

template <typename Ret, typename ...Args>
FuncT<Ret, Args...> *ImportT(char const *name) {
        std::printf("Name: %s\n", name);
        return (FuncT<Ret, Args...> *)dlsym(RTLD_DEFAULT, name); // GetProcAddress on windows
}       

ImportFunc(double, sin, double);
ImportFunc(double, sqrt, double);
ImportFunc(int, fn3, float);

int main() {
        printf("sin(1) = %.3f\n", x_sin(1.0f));
        printf("sqrt(2) = %.3f\n", x_sqrt(2.0f));
}

The symbol will be reference to function and not a function, but IntelliSense should accept that. The reference will be initialized at program startup. Allowing argument names is more problematic, but that should be possible using more function overload magic (see CppReference article for more information).

EDIT: it was simpler indeed, as thing like float (int a, int b) is a valid type in C++:

#define ImportFunc(_type,_name,...) \
        _type (&x_##_name) (__VA_ARGS__) = *ImportT<_type (__VA_ARGS__)>(#_name)

template <typename Func>
Func *ImportT(char const *name) {
        std::printf("Name: %s\n", name);
        return (Func *)dlsym(RTLD_DEFAULT, name); // GetProcAddress on windows
}       

ImportFunc(double, sin, double t);
ImportFunc(double, sqrt, double x);
ImportFunc(int, fn3, float a, char const * b);

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