2010-11-04 7 views
9

Tengo una función en C y estoy tratando de llamar desde Java con JNA:Paso de una clase Java en un vacío * parámetro con JNA

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

De acuerdo con la JNA documentation el vacío * requiere un com.sun.jna.Pointer haber pasó a la función. En Java con JNA Creo que la función anterior será envuelto de la siguiente manera:

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

Los objetos que tienen que vincula al puntero, y se pasa en el parámetro s será clases que implementan Estructura JNA, tales como:

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

Desafortunadamente, el parámetro ls es un número entero que representa la longitud de la clase en bytes. Java no tiene una función sizeof, por lo que agrega un poco más de complejidad. El otro gran problema que tengo es asegurarme de que paso correctamente el contenido del objeto a la memoria nativa y viceversa.

mi código es similar al siguiente:

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

estoy recibiendo un errorque los datos que se pasan es de un tamaño más grande que se espera por la función C.

El código anterior sigue aproximadamente el mismo tipo de pasos as provided out in this answer a una pregunta que trata de un problema similar, pero en C#. He intentado y probado que funciona en C#.

Mi pregunta es similar a another on Stackoverflow, pero se trata de un puntero a una IntByReference en lugar de un puntero a una clase.

Respuesta

6

En primer lugar JNA manejar automáticamente su propio asignaciones de memoria que significa que al siguiente línea es inútil (y puede dañar la pila de memoria):

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

siguiente que también se ocupan de forma automática con los tipos de puntero nativos que significa que las dos líneas siguientes son equivalentes en su caso:

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

y por lo tanto JNA harán myObj.write(); y read para usted.

El siguiente es 100% correcto pero sugieren que inicie sesión len.getValue() antes y después de su llamada a myCfunc (que sould dar 3 * 4 = 12; 3 int de 4 bytes):

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

Si todo de esto es correcto, entonces probablemente tenga un error en el prototipo de su estructura.

Desde mi experiencia, esto se debe principalmente a un archivo de cabecera C obsoleta o una biblioteca obsoleta:

  • está utilizando la versión 2.0 de cabecera que establece que los valores de struct son int, pero su vinculación contra v1.0 biblioteca que toma una estructura de bytes
  • Está utilizando la versión del encabezado 2.0 que establece que los valores de struct son int, pero su vinculación contra v1.9 biblioteca que toma dos enteros y un byte

al final el código debe tener este aspecto:

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 
} 

También puede tratar a voluntaria disminución de valor de len para fines de depuración por ejemplo:

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

Esto no va a hacer lo que quieres probar, pero al menos debe darle la corregir "max len"

Cuestiones relacionadas