2010-11-04 8 views
9

Mam funkcję w C, który próbuję zadzwonić z Java z JNA:Przechodząc klasy Java do void * parametr z JNA

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

Według JNA documentation pustka * wymaga com.sun.jna.Pointer być przekazane do funkcji. W Javy JNA wierzę, że powyższa funkcja zostanie zawinięty w następujący sposób:

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

obiektów, które muszą połączony ze wskaźnikiem i przepuszczono parametru s będzie klas, które wdrażają jna struktury, takie jak:

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

Niestety, parametr ls jest liczbą całkowitą reprezentującą długość klasy w bajtach. Java nie ma funkcji sizeof, więc to dodaje trochę skomplikowania. Innym poważnym problemem, który mam, jest zapewnienie, że poprawnie przekazuję zawartość obiektu do pamięci macierzystej iz powrotem.

mój kod jest podobny do następującego:

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

Dostaję błądże dane przekazywane jest z większego rozmiaru niż oczekuje przez funkcję C.

Powyższy kod z grubsza następujące kroki tego samego rodzaju as provided out in this answer na pytanie dotyczące podobnego problemu, ale w języku C#. Próbowałem i przetestowałem, że działa w języku C#.

Moje pytanie jest podobne do another on Stackoverflow, ale dotyczy raczej wskaźnika do klasy IntByReference niż wskaźnika do klasy.

Odpowiedz

6

Przede wszystkim JNA obsłużyć automatycznie swój własny alokacji pamięci, co oznacza, że ​​do następujących linii jest bezużyteczny (i może spowodować uszkodzenie stosu pamięci):

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

Następny także automatycznie czynienia z rodzimych typów wskaźnikowych co oznacza, że Poniższe obie linie są równoważne w przypadku:

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

a więc JNA zrobi myObj.write(); i read dla Ciebie.

Poniżej 100% poprawne, ale sugerują, że zalogujesz len.getValue() przed i po wywołaniu myCfunc (co sould otrzymując 3 * 4 = 12; 3 INT 4 bajty):

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

Jeśli wszystko z tego jest prawidłowa, prawdopodobnie masz błąd w prototypie twojej struktury.

Z mojego doświadczenia jest to głównie z powodu przestarzałego pliku C nagłówka lub przestarzałej biblioteki:

  • używasz nagłówka w wersji 2.0, który stwierdza, że ​​struktury są wartości int ale twoja łączenie bibliotek, które przed v1.0 przyjmuje strukturę bajtów
  • Używasz nagłówka w wersji 2.0 w którym stwierdza się, że wartości struct są int ale twój powiązanie przeciwko v1.9 biblioteki, która zajmuje dwie ints i bajt

w końcu Twój kod powinien wyglądać tak:

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 
} 

Można również spróbować do dobrowolnie zmniejsz wartość Lena dla celów debugowania np

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

to nie zrobi tego, co wa ale przynajmniej powinno to daje popraw "max len"