2010-11-04 4 views
9

Ho una funzione in C che sto cercando di chiamare da Java con JNA:Passando una classe Java in un void * parametro con JNA

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

Secondo il JNA documentation il vuoto * richiede un com.sun.jna.Pointer essere passato alla funzione. In java con JNA Credo suddetta funzione sarà avvolto come segue:

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

Gli oggetti che devono legata al puntatore, e passato nel parametro s saranno classi che implementano JNA Struttura quali:

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

Sfortunatamente, il parametro ls è un numero intero che rappresenta la lunghezza della classe in byte. Java non ha una funzione sizeof, quindi questo aggiunge un po 'di complessità in più. L'altro problema principale che sto avendo è quello di garantire che sto passando correttamente il contenuto dell'oggetto alla memoria nativa e viceversa.

mio codice è simile al seguente:

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?? 
} 

Ricevo un errore di che i dati passati è di dimensioni maggiori rispetto a quanto previsto dalla funzione C.

Il codice sopra riportato segue lo stesso tipo di passaggi as provided out in this answer a una domanda relativa a un problema simile, ma in C#. Ho provato e testato che funziona in C#.

La mia domanda è simile a another on Stackoverflow, ma che riguarda un puntatore a un IntByReference anziché un puntatore a una classe.

risposta

6

Innanzitutto JNA gestire automaticamente esso la propria allocazioni di memoria che significa che a seguire la linea è inutile (e può danneggiare la pila di memoria):

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

Successivo anche trattare automaticamente con tipi di puntatore nativi che significa che entrambe le linee che seguono sono equivalenti nel tuo caso:

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

e quindi JNA faranno myObj.write(); e read per voi.

Quello che segue è corretta al 100%, ma mi suggeriscono che si accede len.getValue() prima e dopo la chiamata a myCfunc (che Sould danno 3 * 4 = 12; 3 int di 4 byte):

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

Se tutto di questo è corretto quindi probabilmente hai un errore nel prototipo della tua struttura.

Dalla mia esperienza, questo è in gran parte a causa di un file di intestazione C obsoleti o una libreria obsoleta:

  • Si utilizza la versione 2.0 di intestazione in cui si afferma che i valori di struct sono int ma il vostro collegamento contro v1.0 biblioteca che prende una struttura byte
  • Si sta utilizzando la versione 2 dell'intestazione.0 in cui si afferma che i valori di struct sono int ma il vostro collegamento contro v1.9 biblioteca che prende due int e un byte

alla fine il codice dovrebbe essere simile a questo:

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 
} 

Si può anche provare a volontariamente diminuzione del valore di len per scopi di debug ad esempio:

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

Questo non farà quello che si wan't ma almeno dovrebbe dare il correggi "max len"