Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Howto pass funcptr from C++ Class to a C API?

Tags:

c++

c

How can I pass a dynamic generated C++ function as *funcprt to a C API?

The API exports this:

DllImport void api_register_func(char *func_name, void (*funcptr)(char *, char *));

I have to create the function while runtime because I don't know about it before. So I used a class:

class JsFunc
{
    public:
        char * JsFuncName;
        char * JsParameter;

    void RunFunc(char * val1, char * val2)
    {
        printf("\nJsFunc.runFunc executed, JsParameter=%s passed\n",JsParameter);
    }
};

And call it like this:

JsFunc * jsm = new JsFunc ();
jsm->JsFuncName = external_parameter1; 
jsm->JsParameter = external_parameter2; 
api_register_func(external_parameter1, jsm->RunFunc);

But VisualStudio 2015 tells me:

Error C3867 'JsFunc::runFunc': non-standard syntax; use '&' to create a pointer to member VJCS C:\Users\astrauss\Source\Repos\VCJS\VCJS\VCJS.cpp 54

Sorry if the code is bad, I'm not a C/C++ programmer but need to get this running for my daily work. Thanks!

like image 400
Andreas Avatar asked Aug 04 '15 20:08

Andreas


1 Answers

Unfortunately, you don't have very many options here. The API:

DllImport void api_register_func(char *func_name, 
                                 void (*funcptr)(char *, char *));

only lets you provide a function pointer, without any context. So you can pass in a free function or a static member function, but you have no way of providing a member function. If you had a context:

DllImport void better_api_register_func(char *func_name, 
                                        void *context,
                                        void (*funcptr)(void *, char *, char *));

Then you could write a simple lambda:

api_register_func(external_parameter1,
                  jsm, //context
                  [](void *ctxt, char* arg1, char* arg2) {
                      static_cast<JsFunc*>(ctxt)->runFunc(arg1, arg2);
                  });

and you're effectively using a member function as the callback. However, this isn't an option. Instead, you're stuck with using a global variable:

std::unique_ptr<JsFunc> the_global_func;

Which you can allocate at runtime:

the_global_func.reset(new JsFunc);
// set stuff

And then use the global in a lambda. Since it's global, we don't need to (in fact, can't) capture it - which means our lambda can be convertible to a function pointer:

api_register_func(external_paramter1,
                  [](char* arg1, char* arg2) {
                      the_global_func->runFunc(arg1, arg2);
                  });
like image 65
Barry Avatar answered Nov 09 '22 09:11

Barry