2010-11-30 44 views
6

J'essaye d'implémenter du code C en Java en utilisant SWIG 1.3. Maintenant, je de reconstruire du code C en Java existant et de fournir une fonction pointeur vers une fonction Java à la méthode C.Enregistrement de la fonction java comme callback dans la fonction C

Le code C: net.c:

void register_message_handler(context_t *ctx, message_handler_t handler) { 
context->msg_handler = (void (*)(void *, coap_queue_t *, void *)) handler; 
} 

client.c:

void message_handler(context_t *ctx, queue_t *node, void *data) { 
... 
} 

int main(int argc, char **argv) { 
// setup ctx 
register_message_handler(ctx, message_handler); 
} 

Tout ce que je l'ai déjà en Java est:

public static void message_handler(def.SWIGTYPE_p_context_t ctx, def.SWIGTYPE_p_queue_t node, String data) {} 

et cela devrait être enregistré comme rappel de la même manière que dans le code ci-dessus, maintenant en Java:

net.register_message_handler(ctx, message_handler); 

Ce que j'ai trouvé http://www.swig.org/Doc1.3/SWIGDocumentation.html#SWIG_nn30 y compris une référence non définie à la fin de ce chapitre: « Et maintenant, une note finale sur le soutien du pointeur de fonction. Bien que SWIG n'autorise normalement pas l'écriture de fonctions de rappel dans la langue cible, ce peut être accompli avec l'utilisation de typemaps et d'autres fonctions SWIG avancées. Ceci est décrit dans un chapitre ultérieur. » Où cela se réfère à

? J'ai aussi trouvé une solution pour C++, mais est-il possible d'adapter ce à C? Swig c++ w/ Java loses type on polymorphic callback functions morphiques-rappel-fonctions

Merci pour votre aide

+1

j'ai écrit une réponse assez détaillée à ce même problème: http://stackoverflow.com/questions/12210129/how-should-i-write-the-i-file-to-wrap-callbacks- in-java-or-c-sharp – Flexo

Répondre

8

Je me souviens me gratter la tête sur cette référence dans le manuel SWIG trop

Vous pouvez le faire comme suit sans les fonctions ésotériques:..

  • Vous avez besoin d'un mécanisme pour envoyer le rappel C entrant dans Java. Pour cela, vous avez besoin de l'ID d'objet de l'objet que vous appelez et de l'ID de la méthode de votre gestionnaire. Dans votre assistant d'enregistrement C, créez des références globales pour celles-ci et mettez-les en cache afin qu'elles soient utilisées par le rappel.

  • Vous avez également besoin d'un ID de classe et d'un ID de méthode constructeur pour tout ce que vous voulez transmettre au callback Java en tant que paramètre. Vous souhaitez également mettre en cache les références globales à celles-ci.

  • Dans la partie C du rappel, recherchez vos ID de méthode, construisez des arguments et appelez Java.

  • Le thread sur lequel le rappel est activé doit être associé à la machine virtuelle Java (avec la fonction JNI AttachCurrentThread()). C'est ici que vous obtenez votre pointeur JNIEnv. Ce pointeur n'est valide que dans le contexte du thread que vous avez appelé AttachCurrentThread() à partir de! Cela signifie que si vous recevez des rappels sur plusieurs threads, vous devez mettre en cache le JNIEnv * dans le stockage local de threads.

  • Assurez-vous de vérifier les valeurs de retour après le retour de JNI Fonctions de

  • Assurez-vous de vérifier ExceptionOccurred() après tout et tous les appels de nouveau dans Java. Ne pas le faire vous met vraiment dans le pétrin, difficile de déboguer. J'ai trouvé cela relativement facile à déboguer avec Eclipse et Visual Studio comme suit: Démarrez le programme principal Java à partir d'Eclipse, attachez Visual Studio Debugger à ce processus. Vous pouvez définir des points d'arrêt de chaque côté.

+0

Bon conseil! +1 – Nowaker