Je veux utiliser epanet.dll afin de l'appeler, je dois créer ma passerelle dll.Problème JNI: appeler en Java une DLL qui utilise une DLL tierce
J'ai créé la classe Java
public class Epanet {
//Native method declaration
native int ENopen(String fileInput, String fileOutput, String optBinFileOut);
native int ENsaveinpfile(String file);
native int ENclose();
native int ENsolveH();
native int ENsaveH();
native int ENopenH();
//native int ENrunQ(long *);
//Load the library
static {
System.loadLibrary("epanet2");
}
}
Puis javah créé de fichier .h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class Epanet */
#ifndef _Included_Epanet
#define _Included_Epanet
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jint JNICALL Java_Epanet_ENopen (JNIEnv *, jobject, jstring, jstring, jstring);
JNIEXPORT jint JNICALL Java_Epanet_ENsaveinpfile (JNIEnv *, jobject, jstring);
JNIEXPORT jint JNICALL Java_Epanet_ENclose (JNIEnv *, jobject);
JNIEXPORT jint JNICALL Java_Epanet_ENsolveH (JNIEnv *, jobject);
.....
.....
#ifdef __cplusplus
}
#endif
#endif
Ensuite, j'ai créé le fichier .c qui devrait appeler epanet2 dll
#include "jni.h"
#include <stdio.h>
#include "myDll.h"
#include "epanet2.h"
JNIEXPORT jint JNICALL Java_Epanet_ENopen
(JNIEnv *env, jobject obj, jstring fichIn, jstring fichOut, jstring fichBin){
const char *CStringFichIn = (*env)->GetStringUTFChars(env,fichIn,NULL);
const char *CStringFichOut = (*env)->GetStringUTFChars(env,fichOut,NULL);
const char *CStringFichBin = (*env)->GetStringUTFChars(env,fichBin,NULL);
int result;
result = ENepanet (CStringFichIn, CStringFichOut, CStringFichBin, NULL);
(*env)->ReleaseStringUTFChars(env, fichIn, CStringFichIn);
(*env)->ReleaseStringUTFChars(env, fichOut, CStringFichOut);
(*env)->ReleaseStringUTFChars(env, fichBin, CStringFichBin);
return result;
}
JNIEXPORT jint JNICALL Java_Epanet_ENsaveinpfile
(JNIEnv *env, jobject object, jstring fichOut){
const char *CStringFichOut;
int result;
CStringFichOut = (*env)->GetStringUTFChars(env,fichOut,NULL);
result = ENsaveinpfile (CStringFichOut);
return result;
}
JNIEXPORT jint JNICALL Java_Epanet_ENclose
(JNIEnv *env, jobject object){
int result;
result = ENclose();
return result;
}
JNIEXPORT jint JNICALL Java_Epanet_ENsolveH
(JNIEnv *env, jobject object){
int result;
result = ENsolveH();
return result;
}
JNIEXPORT jint JNICALL Java_Epanet_ENsaveH
(JNIEnv *env, jobject object){
int result;
result = ENsaveH();
return result;
}
JNIEXPORT jint JNICALL Java_Epanet_ENopenH
(JNIEnv *env, jobject obj){
int result;
result = ENopenH();
return result;
}
Et puis compilez. Visual C++ crée ma DLL. J'ai copié les deux DLLs dans system32. Ensuite, j'essaie d'utiliser ma DLL.
public class NewClass {
private native void ENopen(String f1, String f2, String f3);
public static void main(String[] args) {
System.out.println("started");
new NewClass().ENopen("C:\\Red2.inp", "C:\\salaida.txt", "");
System.out.println("finished");
}
static {
System.loadLibrary("myDll");
}
}
Je reçois cette erreur:
started
Exception in thread "main" java.lang.UnsatisfiedLinkError: NewClass.epanet(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String)V
at NewClass.epanet(Native Method)
at NewClass.main(NewClass.java:18) Java Result: 1
Si j'ai supprimé les bibliothèques que je reçois des erreurs en disant qu'il ne peut pas trouver les bibliothèques donc il y a un problème quelque part. Je dois dire qu'un ami m'a donné sa DLL qui fonctionne pour lui mais ça ne marche pas pour moi. J'ai la même erreur.
Devinez? Une autre question est de savoir comment appeler cette méthode native // native int ENrunQ (long *); ?
Donc, c'est ce que vous me proposez (surtout pour le second commentaire):
classe Mon Epanet charge ma dll et non la dll EPANET (tiers un).
public class Epanet {
//Native method declaration
native int ENopen(String fileInput, String fileOutput, String optBinFileOut);
native int ENsaveinpfile(String file);
native int ENclose();
native int ENsolveH();
native int ENsaveH();
native int ENopenH();
//native int ENrunQ(long *);
//Load the library
static {
System.loadLibrary("myDll");
}
}
Et ma classe de test ne devrait pas le charger. En fait, il ne devrait pas être chargé car la classe Epanet le fait.
public class NewClass {
public static void main(String[] args) {
System.out.println("started");
new Epanet().ENopen("C:\\Red2.inp", "C:\\salida.txt", "");
System.out.println("finished");
}
}
Ensuite, mon dll wrapper devrait ressembler à ceci:
#include "jni.h"
#include <stdio.h>
#include "myDll.h"
#include "epanet2.h"
JNIEXPORT jint JNICALL Java_Epanet_ENopen
(JNIEnv *env, jobject obj, jstring fichIn, jstring fichOut, jstring fichBin){
const char *CStringFichIn = (*env)->GetStringUTFChars(env,fichIn,NULL);
const char *CStringFichOut = (*env)->GetStringUTFChars(env,fichOut,NULL);
const char *CStringFichBin = (*env)->GetStringUTFChars(env,fichBin,NULL);
int result;
result = ENopen (CStringFichIn, CStringFichOut, CStringFichBin);
(*env)->ReleaseStringUTFChars(env, fichIn, CStringFichIn);
(*env)->ReleaseStringUTFChars(env, fichOut, CStringFichOut);
(*env)->ReleaseStringUTFChars(env, fichBin, CStringFichBin);
return result;
}
Ou plus comme ceci:
#include "jni.h"
#include <stdio.h>
#include <windows.h>
#include "myDll.h"
#include "epanet2.h"
typedef int (* FPTR)(char *, char *, char*);
JNIEXPORT jint JNICALL Java_Epanet_ENopen
(JNIEnv *env, jobject obj, jstring fichIn, jstring fichOut, jstring fichBin){
HMODULE dllHandle = LoadLibrary("epanet2.dll"); // cargar librería
const char *CStringFichIn = (char *)(*env)->GetStringUTFChars(env,fichIn,NULL);
const char *CStringFichOut = (char *) (*env)->GetStringUTFChars(env,fichOut,NULL);
const char *CStringFichBin = (char *)(*env)->GetStringUTFChars(env,fichBin,NULL);
int result;
FPTR ENopen = (FPTR) GetProcAddress(dllHandle, "ENopen");
result = ENopen (CStringFichIn, CStringFichOut, CStringFichBin);
(*env)->ReleaseStringUTFChars(env, fichIn, CStringFichIn);
(*env)->ReleaseStringUTFChars(env, fichOut, CStringFichOut);
(*env)->ReleaseStringUTFChars(env, fichBin, CStringFichBin);
FreeLibrary(dllHandle); // descargar librería
return result;
}
Aussi, savez-vous comment appeler cette fonction?
native int ENrunQ(long *);
Je ne sais pas comment faire obtenir de longues * à mydll parce que string -> jstring ou int -> JINT mais long * ->? ou int * ->?
Vous avez vérifié que vous ne disposez pas d'un DLL défectueux dans votre dossier bin? – dacwe
Pourquoi avez-vous deux appels 'loadLibrary (..)'? Vous avez seulement une interface! – dacwe
Je ne sais pas comment vérifier s'il y a une DLL défectueuse. Tout fonctionne bien. – Alberto