JAVA, JNI, DLL, C/C++ ... Esto no es basico:

fcordoba
11 de Abril del 2002
Hola Socios, mi duda es:

Partimos de que tenemos una dll con funciones C para insertar y extraer estructuras en una zona compartida de memoria de la propia dll.
¿Como recuperar una estructura devuelta por la dll de C a traves de codigo JNI, en mi programa JAVA?

Espero vuesto bombardeo de respuestas ;-)

salu2 a to2

David Martinez
11 de Abril del 2002
No se puede de la manera que preguntas. Lo que necesitas hacer es hacer una clase como ProxyParaMisFunciones.java, y una clase equivalente a la estructura en C, digamos MiSuperEstructura. En esta clase haces metodos como

package mi.paquete;

public MiSuperEstructura native obtenMiEstructura();

No le pongas cuerpo a las funciones.

Dentro de tu declaracion de clase, escribe
static {
System.loadLibrary("miproxydllparajava.dll");
}

Asegurate de que el directorio donde vas a poner miproxydllparajava.dll se encuentre en el java.library.path

Ahora utiliza javah para generar un archivo C de cabecera. Va a generar algo asi como tu_paquete_MiSuperEstructura.h

Ahora tu necesitas escribir codigo en C/C++ "proxy" para ejecutar tus funciones C. En jdk1.3/include/jni.h puedes encontrar las macros para hacer interface con java desde C.

Para crear nuevos objetos desde C a traves de Java, necesitas hacer dos cosas. Primero, utilizar la macro "FindClass" asi:

(*env)->FindClass(env,"mi/paquete/MiSuperEstructura")

Despues, necesitas crear un nuevo objeto de esa clase con NewObject (típicamente yo no lo hago, asi que no te puedo dar la función).

Como crear nuevos objetos desde C es un relajo y soy muy holgazán, prefiero utilizar mi clase en Java para crear los objetos desde un método y llamar este método desde C con todos los valores de la estructura.

He aqui una funcion que llama a System.out.println, que te dara una idea de como encontrar clases, llamar "getters" y ejecutar metodos:


/**
* Un System.out.println() para C
*/
void SYSTEMOUTPRINTLN(JNIEnv *env, char *str) {

jstring jstr = (*env)->NewStringUTF(env, str);
jclass System_class = (*env)->FindClass(env, "java/lang/System");
jfieldID fid_out = (*env)->GetStaticFieldID(env, System_class, "out","Ljava/io/PrintStream;");
jobject out = (*env)->GetStaticObjectField(env, System_class, fid_out);
jclass PrintStream_class = (*env)->FindClass(env,"java/io/PrintStream");
jmethodID mid_println = (*env)->GetMethodID(env,PrintStream_class,"println", "(Ljava/lang/String;)V");
if (mid_println == 0) {
printf("WOW! Couldn't find System.out.println! Message was %s", str);
return;
}
(*env)->CallVoidMethod(env, out, mid_println, jstr);
}

Tu codigo en C necesita cargar tu otro DLL, y ejecutar las funciones cuando tu otro codigo (en java) le diga que lo debe hacer. Normalmente procuro mantener tanto codigo en Java como sea posible, por aquello de la dificultad para encontrar bugs despues.

Espero que esto te ayude un poco.

Saludos!


David Martinez
11 de Abril del 2002
Ah, tan menso... En mi ejemplo la clase que necesita ser nativa y cargar el DLL es ProxyParaMisFunciones, y el codigo que escribi pone el codigo nativo en MiSuperEstructura.. Pero espero que aún así se entienda :-)

Saludos!