IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

C++ et JNI : Pointeur et méthodes Callback


Sujet :

C++

  1. #1
    Membre confirmé
    Avatar de giminik
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    303
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 303
    Points : 482
    Points
    482
    Par défaut C++ et JNI : Pointeur et méthodes Callback
    Bonjour,

    Le problème dont je vais vous parler doit être côté C++ et non Java JNI.
    Nous tentons d'intercepter des évènements windows via les hooks, et de remonter ces évènements à Java via JNI.

    Nous arrivons bien à détecter les évènement grâce aux hooks. Pour communiquer avec Java, nous disposons d'un pointeur vers la JVM Java, le problème, c'est que ce pointeur vers la JVM n'est pas valide dans les fonctions de callback (j'ignore pourquoi) bien que nous l'ayons au préalable copié dans une variable globale depuis une fonction normale. Nous n'avons pas ce problème avec un type entier par exemple, ce problème ne survient qu'avec les pointeurs à priori...

    Avez vous une idée du problème ? Cela doit sans doute être dû à une subtilité des fonctions de callback ?
    Comment contourner le problème ? Nous avons juste besoin de copier ce pointeur depuis une fonction non callback pour y avoir accès dans une fonction de callback justement.

    Merci d'avance de votre aide précieuse :-)

  2. #2
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Le problème a priori, c'est que le pointeur vers JNIEnv, n'est valide que dans le thread qui l'a requis. Il n'est donc pas possible de passer ce type de pointeur d'un thread vers un autre. Le coup de la variable globale est donc une très mauvaise idée.

    Lorsque l'on se trouve dans le corps d'une callback, on est dans un thread différent de son thread principal.

    http://www.science.uva.nl/ict/ossdoc...ting/sync.html

  3. #3
    Membre confirmé
    Avatar de giminik
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    303
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 303
    Points : 482
    Points
    482
    Par défaut
    Merci pour ta réponse.
    On m'a conseillé d'utiliser la fonction ReadProcessMemory pour effectuer une copie de JNIEnv mais il semble que cela ne copie pas complètement la structure car elle contient également des pointeurs... Est-ce que cette solution est viable ?

    The JNI interface pointer (JNIEnv *) is only valid in the current thread. You must not pass the interface pointer from one thread to another, or cache an interface pointer and use it in multiple threads. The Java Virtual Machine will pass you the same interface pointer in consecutive invocations of a native method from the same thread, but different threads pass different interface pointers to native methods.
    Ok, mais alors comment récupérer le pointeur vers JNIEnv depuis un autre thread ?

    Check the use of global variables carefully. Multiple threads might be accessing the global variables at the same time. Make sure that you put in appropriate locks to ensure safety.
    Il n'est vraiment pas possible d'utiliser une variable globale ?

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Apparemment, tu ne peux pas appeler la JNI ainsi depuis un hook.
    Mais tu peux toujours prévenir un autre thread depuis le hook, un thread qui aurait un pointeur valide sur la JNI...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Prend ma réponse avec des pincettes, je suis un peu rouillé du JNI.
    Citation Envoyé par giminik Voir le message
    On m'a conseillé d'utiliser la fonction ReadProcessMemory pour effectuer une copie de JNIEnv mais il semble que cela ne copie pas complètement la structure car elle contient également des pointeurs... Est-ce que cette solution est viable ?
    Je ne pense vraiment pas que ce soit une bonne idée. C'est l'environnement JNI qui est local à un thread, le dupliquer ne ferait que créer des problèmes.

    Ok, mais alors comment récupérer le pointeur vers JNIEnv depuis un autre thread ?
    Je ne suis pas expert, mais j'essaierai les deux choses suivantes:
    - demander un pointeur vers l'environnement dans le thread de la callback (à partir de du pointeur sur la JVM). Je ne me rappelle pas si c'est possible, donc à vérifier.
    - Traiter toutes les callback dans le thread principal. Cela implique de mettre en place un méchanisme de communication et de synchronisation entre les callbacks et le thread principal (la callback empile un event, prévient le principal, le principal le traite, etc...)

    Intuitivement, je préfère la seconde solution. Elle est plus coûteuse à mettre en place, mais elle a le mérite d'être très claire en terme d'archi.

    Il n'est vraiment pas possible d'utiliser une variable globale ?
    Clairement et définitivement non.


    EDIT: Après une petite recherche je suis retombé sur ça
    http://java.sun.com/docs/books/jni/html/other.html

    Le paragraphe 8.1.4 répond au point 1. Je pense que la doc est vieille et que la syntaxe a du changer.

    Cela ne change rien à ma remarque précédente. Pour moi la vrai solution passe par avoir tout le traitement Java des callback dans un thread unique.

  6. #6
    Membre confirmé
    Avatar de giminik
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    303
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 303
    Points : 482
    Points
    482
    Par défaut
    La solution 8.1.4 m'aurait bien arrangé, malheureusement je retombe sur le même problème de pointeur non accessible dans le processus des méthodes callback.

    Nous avions pensé à utiliser de la mémoire partagée, il me faudrait alors effectuer une copie de JavaVM, est-ce plus propre que de tenter une copie de JNIEnv ?

    As tu plus d'informations sur la solution numéro 2 qui n'utilise qu'un seul thread ?
    Avec éventuellement un petit lien sur un exemple de code ?

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Mémoire partagée, variable globale ou autre ça ne marchera pas.
    L'environnement JNI dépend du thread. Quelque soit la méthode de partage, c'est incontournable. Ce que tu proposes reviendrait à recréer une JVM à chaque appel d'une callback.

    Pour la méthode 2, c'est assez simple. Sans connaitre plus ton problème, j'utiliserai une pattern de type commande.
    Au lieu d'exécuter un traitement directement dans le corps de la callback. La callback crée une instance de commande et l'empile dans une structure FIFO et notifie le thread qui possède la JVM (en allouant un jeton sur un sémaphore par exemple).
    Le thread JVM traite la commande (en appelant la méthode execute() si on suit la pattern).

    Je n'ai pas de code disponible sous la main, mais c'est assez classique comme implémentation. Je peux éventuellement te filer un coup de pouce, mais je n'ai pas la dispo pour écrire le code entièrement.

  8. #8
    Membre confirmé
    Avatar de giminik
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    303
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 303
    Points : 482
    Points
    482
    Par défaut
    La solution que tu proposes m'intéresse.
    Pour la file, pas de problème et pour le design pattern commande, je suis déjà en train de me documenter la dessus.
    Par contre, là où je vais galérer c'est sur la manière de faire la communication entre les threads depuis les méthodes de callback.
    As tu, à défaut d'un bout de code, les noms des fonctions qui permettent de faire la communication entre le thread principal et les fonctions de callback, je devrais pouvoir me débrouiller. Si jamais j'ai des soucis, je reviendrai alors t'embêter
    Merci en tout cas de m'éclaircir.
    Matthieu

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Citation Envoyé par giminik Voir le message
    As tu, à défaut d'un bout de code, les noms des fonctions qui permettent de faire la communication entre le thread principal et les fonctions de callback, je devrais pouvoir me débrouiller. Si jamais j'ai des soucis, je reviendrai alors t'embêter
    Ce sont des threads, pas des processus indépendants. Il n'y a donc pas de problèmes à partager des structures de données entre eux, notamment une liste de commandes par exemple.
    Ce qu'il te faut ensuite, c'est un "objet de synchronisation" qui évite que qu'une callback modifie la liste en même temps que le thread JVM. Ceci dépend de ton OS, mais c'est assez simple. Je te conseille de faire une recherche sur le modèle "Producteur/Consommateur" avec sémaphore. Tu auras sûrement le bon bout de code pour ça.

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2006
    Messages
    15
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Tunisie

    Informations forums :
    Inscription : Août 2006
    Messages : 15
    Points : 13
    Points
    13
    Par défaut
    Citation Envoyé par giminik Voir le message
    La solution 8.1.4 m'aurait bien arrangé, malheureusement je retombe sur le même problème de pointeur non accessible dans le processus des méthodes callback.

    Nous avions pensé à utiliser de la mémoire partagée, il me faudrait alors effectuer une copie de JavaVM, est-ce plus propre que de tenter une copie de JNIEnv ?

    As tu plus d'informations sur la solution numéro 2 qui n'utilise qu'un seul thread ?
    Avec éventuellement un petit lien sur un exemple de code ?
    pour recuperer JNIEnv je pense qu'il faut attacher le thread a la JVM !

    j'ai utilisé une fois ce code ... peut etre it help !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    JNIEnv	*env;
    jvmtiEnv	*jvmti;
    jint	rc;
    jvmtiError	 err;	
     
    if(javaVM->AttachCurrentThread((void **)&env, NULL) >= 0){printf("Thread attaché !\n");}
    else
    	printf("Error: Error on the attach current thread thing!\n");
     
    rc = javaVM->GetEnv((void **)&jvmti, JVMTI_VERSION_1);
    	if (rc  != JNI_OK) {
    		printf("ERROR: Unable to create jvmtiEnv, rc=%d\n", rc);
    		return -1;
    		}
    Merci !

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Une minute...
    Depuis quand les hooks s'exécutent-ils hors du thread principal mais forcément dans le même process ?

    S'il s'agit de hooks qui s'exécutent hors du thread principal, alors ils s'exécutent dans le thread qui a lancé l'événement, c'est-à-dire potentiellement un thread d'un autre processus...
    À ce moment-là, des IPCs seront nécessaires...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    bonne remarque, j'y connais rien en hook.
    Mais si l'OP pouvait passer une variable globale commune, y'a des chances qu'il soit dans le même processus non?

  13. #13
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Le problème, c'est que la variable globale en question n'était pas vraiment passée.
    Ça expliquerait que le pointeur soit carrément invalide au lieu d'avoir simplement des conséquences bizarres...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  14. #14
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    laissons le répondre
    Si ça devient trop technique giminik, je suis dispo en MP

  15. #15
    Membre confirmé
    Avatar de giminik
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    303
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 303
    Points : 482
    Points
    482
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    S'il s'agit de hooks qui s'exécutent hors du thread principal, alors ils s'exécutent dans le thread qui a lancé l'événement, c'est-à-dire potentiellement un thread d'un autre processus...
    Comment puis-je le vérifier ?
    Il s'agit en fait d'une classe Java qui lance le code natif (qui est donc une dll). Dans cette dll il y a des hook pour écouter une fenêtre windows en particulier : savoir si cette fenêtre est redimensionnée ou repainte notamment.

    Je tiens à préciser qu'avec une mémoire partagée, nous arrivons à transmettre des valeurs de type entier dans une variable.

    J'ai une petite question subsidiaire : savez-vous pourquoi lorsqu'on fait des printf ou cout dans les fonctions de callback, rien ne s'affiche dans la console ? Je suis obligé d'utiliser des Beep() pour faire du deboggage...

  16. #16
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Si tu disposes d'une mémoire partagée, tu disposes donc d'un canal pour partager une liste de commande. Il te faudra un objet de synchro, et cela existe de base sous windows, que tu aies affaire avec des thread ou des processus.

    Pour le coup de ton printf c'est lié. La console est liée à ton programme principal. Si la callback est appelée dans un autre processus, elle n'a aucun accès à la console. Par contre, le haut-parleur est commun
    Ce qui explique que le beep fonctionne. Un système de fichier de log serait néanmoins beaucoup plus propre (et utile sur le long terme).

  17. #17
    Membre confirmé
    Avatar de giminik
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    303
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 303
    Points : 482
    Points
    482
    Par défaut
    Ok, donc pour résumer, je dois utiliser la mémoire partagée pour stocker tout ce que je souhaite, sauf des pointeurs, c'est bien ça ?
    Je vais donc stocker dans cette mémoire partagée, une file, et lui envoyer des commandes via le pattern du même nom.
    Pour éviter les problèmes d'accès concurrents, je mets un mutex ou équivalent.
    Et dans un thread séparé, j'aurai un while (true) qui ira vérifier si des commandes sont disponibles dans la file (toujours avec le mutex pour éviter les problèmes d'accès concurrents). J'ai peur que ce while (true) consomme trop de ressources CPU...
    J'ai juste ?

  18. #18
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Ce que tu fais, c'est vraiment un hook ou c'est du subclassing ?

    Je pose la question, car j'ai vu la même confusion en .Net un peu plus tôt...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  19. #19
    Membre confirmé
    Avatar de giminik
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    303
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 303
    Points : 482
    Points
    482
    Par défaut
    Euh, je ne connais pas la différence entre les deux.
    Je ne suis pas à l'origine du code mais on m'a dit qu'il s'agissait de hook.
    Si ça peut aider, nous utilisons la fonction suivante pour sa mise en place :
    SetWindowsHookEx()

  20. #20
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    C'est donc bien un hook.
    Le subclassing, c'est joué avec SetWindowLong() pour remplacer la procédure de fenêtre.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

Discussions similaires

  1. Pointeur de Méthode et RTTI
    Par ShaiLeTroll dans le forum Delphi
    Réponses: 6
    Dernier message: 16/01/2007, 16h04
  2. TIdFTP, pointeur de méthode et procédure normale
    Par marcpleysier dans le forum Delphi
    Réponses: 4
    Dernier message: 05/01/2007, 10h30
  3. [API Win32 C++ sans MFC] Une méthode CALLBACK ?
    Par kidpaddle2 dans le forum Windows
    Réponses: 6
    Dernier message: 17/09/2006, 15h42
  4. [C++] Tableau de pointeurs de méthode ?
    Par Castagnems dans le forum C++
    Réponses: 13
    Dernier message: 15/05/2006, 16h45
  5. Pointeur de méthode
    Par John Fullspeed dans le forum Langage
    Réponses: 3
    Dernier message: 24/09/2004, 16h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo