2015-08-04 12 views
6

Come posso passare una funzione C++ generata dinamicamente come * funcprt a un'API C?Come passare funcptr dalla classe C++ a un'API C?

Le esportazioni API questo:

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

devo creare la funzione, mentre il runtime, perché io non so parlare prima. così ho usato una classe:

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

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

e chiamarlo in questo modo:

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

Ma VisualStudio 2015 mi dice:

Errore C3867 'jsFunc :: runFunc': non sintassi standard; uso '&' per creare un puntatore a membro VJCS C: \ Users \ astrauss \ Source \ Repos \ VCJS \ VCJS \ VCJS.cpp 54

Scusate se il codice è male, io non sono un Programmatore C/C++ ma ho bisogno di farlo funzionare per il mio lavoro quotidiano. Grazie!

+0

Non si ha accesso al C++ 11? – Kupiakos

+3

Sfortunatamente la maggior parte di questo non ha assolutamente senso. Sembra che tu stia chiedendo della soluzione invece di chiedere del problema ([Problema XY] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)). Prova a modificare la tua domanda – Amit

+0

Non puoi farlo precisamente, dal momento che RunFunc ha un parametro "nascosto" 'questo' di cui C non ne sa nulla (che tiene un puntatore al tuo oggetto' jsm'. Dovrai trovare in qualche modo è possibile "stivare" l'indirizzo di 'jsm' da qualche parte. –

risposta

1

Purtroppo, non ci sono molte opzioni qui. L'API:

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

consente solo di fornire un puntatore a funzione, senza alcun contesto. Quindi puoi passare una funzione libera o una funzione membro statico, ma non hai modo di fornire una funzione membro. Se tu avessi un contesto:

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

allora si potrebbe scrivere un semplice lambda:

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

e il gioco è efficace utilizzando una funzione di membro come callback. Tuttavia, questa non è un'opzione. Invece, sei bloccato con l'utilizzo di una variabile globale:

std::unique_ptr<JsFunc> the_global_func; 

Quale è possibile allocare a runtime:

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

E quindi utilizzare il globale in una lambda. Dal momento che è globale, non abbiamo bisogno di (in realtà, non può) catturarlo - il che significa che la nostra lambda può essere convertibile in un puntatore a funzione:

api_register_func(external_paramter1, 
        [](char* arg1, char* arg2) { 
         the_global_func->runFunc(arg1, arg2); 
        }); 
+0

Grazie mille! Questo dovrebbe funzionare per me. Al momento non posso provarlo con l'API ma compila :) – Andreas

+0

Barry, il tuo codice funziona per uno "the_global_func". Ma non ho trovato un modo per farlo per più di uno. C'è un'altra possibilità che definire più di un "the_global_func" (the_global_func1, the_global_func1, ...)? Ho provato a mettere the_global_func in un vettore, ma non posso passare l'indice a api_register_func. Quando cambio [] (char ... in [=] (char ... posso passare l'indice ma poi il lambda restituisce un altro tipo Grazie ancora! – Andreas

Problemi correlati