2010-11-04 30 views
9

J'ai une fonction en C que je suis en train d'appeler à partir de Java avec JNA:Le passage d'une classe Java dans un vide * paramètre avec la JNA

int myCfunc(void *s, int *ls); 

Selon le JNA documentation le vide * nécessite un com.sun.jna.Pointer être passé à la fonction. En java avec la JNA, je crois que la fonction ci-dessus sera enveloppé comme suit:

public interface myWrapper extends Library{ 
    public int myCfunc(Pointer s, IntByReference ls); 
} 

Les objets qui doivent lié au pointeur, et passé en paramètre s seront classes qui mettent en œuvre la structure de la JNA, telles que:

public class myClass extends Structure{ 
    public int x; 
    public int y; 
    public int z; 
} 

Malheureusement, le paramètre ls est un entier représentant la longueur de la classe en octets. Java n'a pas de fonction sizeof, ce qui ajoute un peu de complexité. L'autre problème majeur que j'ai est de m'assurer que je passe correctement le contenu de l'objet à la mémoire native et vice-versa.

mon code est similaire à ce qui suit:

import com.sun.jna.Native; 
import com.sun.jna.Pointer; 
import com.sun.jna.Structure; 
import com.sun.jna.ptr.IntByReference; 

public void foo(){ 
    myWrapper wrapper = (myWrapper) Native.loadLibrary("SomeDllWithLegacyCode", myWrapper.class); 

    myClass myObj = new myClass(); 
    myObj.x = 1; 
    myObj.y = 2; 
    Pointer myPointer = myObj.getPointer(); 

    int size = Native.getNativeSize(myClass.class); 
    IntByReference len = new IntByReference(size); 

    myObj.write(); //is this required to write the values in myObj into the native memory?? 
    wrapper.myCfunc(myPointer, len); 
    myObj.read(); //does this read in the native memory and push the values into myObj?? 

    myPointer.clear(size); //is this required to clear the memory and release the Pointer to the GC?? 
} 

Je reçois une erreur qui les données transmises est d'une taille plus grande que devrait par la fonction C.

Le code ci-dessus suit à peu près le même type d'étapes as provided out in this answer à une question traitant d'un problème similaire, mais en C#. J'ai essayé et testé que cela fonctionne en C#.

Ma question est similaire à another on Stackoverflow, mais cela concerne un pointeur vers un IntByReference plutôt qu'un pointeur vers une classe.

Répondre

6

tout d'abord la JNA gère automatiquement ses propres allocations de mémoire qui signifie que la ligne suivante est inutile (et peut endommager la pile de mémoire):

myPointer.clear(size); //is this required to clear the memory and release the Pointer to the GC?? 

Ensuite, il traite automatiquement avec les types de pointeur natif ce qui signifie que les deux lignes ci-dessous sont équivalentes dans votre cas:

public int myCfunc(Pointer s, IntByReference ls); 
public int myCfunc(myClass s, IntByReference ls); 

et donc la JNA vont faire pour vous myObj.write(); et read.

Ce qui suit est 100% correct, mais je suggère que vous vous connectez len.getValue() avant et après votre appel à myCfunc (qui Sould donner 3 * 4 = 12; 3 int 4 octets):

int size = Native.getNativeSize(myClass.class); 
IntByReference len = new IntByReference(size); 

Si tous de ceci est correct alors vous avez probablement une erreur dans le prototype de votre structure.

D'après mon expérience cela est principalement dû à un fichier d'en-tête pas à jour C ou une bibliothèque obsolète:

  • Vous utilisez la version d'en-tête 2.0 qui stipule que les valeurs de struct sont int, mais votre liaison contre v1.0 bibliothèque qui prend une structure d'octets
  • Vous utilisez l'en-tête version 2.0 qui indique que les valeurs de struct sont int, mais votre liaison contre v1.9 de la bibliothèque qui prend deux ints et un octet

à la fin de votre code devrait ressembler à ceci:

public void foo(){ 
    myWrapper wrapper = (myWrapper) Native.loadLibrary("SomeDllWithLegacyCode", myWrapper.class); 

    myClass myObj = new myClass(); 
    myObj.x = 1; 
    myObj.y = 2; 

    int size = Native.getNativeSize(myClass.class); 
    IntByReference len = new IntByReference(size); 

    //log len.getValue 
    wrapper.myCfunc(myObj, len); 
    //log len.getValue 
} 

Vous pouvez également essayer à volontairement diminution de la valeur de len à des fins de débogage par exemple:

IntByReference len = new IntByReference(size-1); 
IntByReference len = new IntByReference(size-2); 
IntByReference len = new IntByReference(size-3); 
//... 
IntByReference len = new IntByReference(size-11); 

Ce ne sera pas ce que vous wan't mais au moins il devrait vous donner la corriger "max len"