2010-11-21 6 views
1

Я хочу использовать epanet.dll, чтобы его назвать. Мне нужно создать мою dll-мост.Проблема JNI: вызов в Java dll, использующий стороннюю dll

Я создал класс 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"); 
    } 
} 

Затем javah создал де .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 

Затем я создал файл .c, который должен вызывать DLL epanet2

#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; 
} 

И затем скомпилируйте. Visual C++ создает мою dll. Я скопировал обе библиотеки dll в system32. Затем я пытаюсь использовать свою 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"); 
    } 
} 

Я получаю эту ошибку:

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 

Если я удалил библиотеки я получаю ошибки заявив, что не может найти библиотеки, так что проблема где-то. Должен сказать, что друг дал мне свою dll, которая работает для него, но это не работает для меня. Я получаю ту же ошибку.

Любое предположение? Другой вопрос: как вызвать этот собственный метод // native int ENrunQ (long *); ?

Так это то, что вы предлагаете мне (в основном для второго комментария):

Моего EPANET класс загружает мой DLL, а не в EPANET DLL (третья сторона один).

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"); 
    } 
} 

И мой класс испытаний не должен его загружать. На самом деле, он не должен загружать какой-либо сигнал, который делает класс Epanet.

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"); 
    } 
} 

Тогда моя длл обертка должна выглядеть следующим образом:

#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; 
} 

Или больше, как это:

#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; 
} 

Кроме того, вы знаете, как назвать эту функцию?

native int ENrunQ(long *);

Я не знаю, как получить длинный * в MyDLL, потому что строка -> jstring или Int -> JINT но долго * ->? или int * ->?

+0

Вы проверили, что у вас нет неисправной библиотеки, лежащей в вашей папке с bin? – dacwe

+0

Почему у вас есть два 'loadLibrary (..)' звонка? У вас есть только один интерфейс! – dacwe

+0

Я не знаю, как проверить, есть ли неисправная dll. Все работает нормально. – Alberto

ответ

0

Моих два цента:

обертка DLL содержит реализации для нативных методов в вашем Epanet класса, а не для нативного метода вы звоните в тестовом коде (обратите внимание на имя класса в StackTrace). Я думаю, вы должны использовать new Epanet().ENopen("C:\\Red2.inp", "C:\\salaida.txt", "");.

Кроме того, статический инициализатор для Epanet должен загружать вашу DLL, а не обернутую библиотеку (ОС позаботится об этом, если ваша оболочка была построена правильно).

+0

Я изменил звонок к новому Epanet(). ENopen (......), и теперь я получаю сообщение об ошибке. Это здорово после недели, работая над этим: D – Alberto

+0

Второй комментарий, который вы говорите, я не знаю, как это исправить. на этом ограничено, поскольку нет учебников/демонстраций, которые подходят для моей DLL. – Alberto

0

Вы предоставили источник для двух классов Java и только одну из встроенных реализаций. Что усложняет нам понимание.Избавьтесь от NewClass.

Вы хотите, чтобы ваш класс Java Epanet загрузил его в оболочку System.loadLibrary(), а затем ваша обложка dll автоматически загрузит файл epanet.dll.

Что касается передачи длинного * в ваш собственный код, вы не можете. Умение создавать класс оболочки java-c заключается в том, что вы не можете просто напрямую вызвать оригинальные методы! Вы можете пройти достаточно долго, но тогда любые изменения, внесенные в длинный, будут потеряны. Таким образом, вы можете либо передать измененный java-объект на ваш обертковый вызов, либо изменить его, или более просто иметь собственный метод, изменяющий некоторое состояние класса Epanet.

+0

Пожалуйста, проверьте новое решение, которое я разместил. – Alberto

+0

Что касается второго комментария, я думаю, что я вас понимаю. Мой класс Java перейдет к моей dll длиной jlong. Затем я создаю в mydll длинный var, скопирую в него jlong, и я вызываю собственный метод с & long. Как вы говорите, когда моя dll вернется, я потеряю любую модификацию в длинном var. – Alberto

0

Я рекомендую попробовать Dependency Walker, чтобы увидеть, есть ли другие DLL-файлы, которые могут вам понадобиться (например, возможно, вам не хватает времени выполнения Microsoft C).

+0

T здесь была проблема где-то. Я перестроил все с нуля, и он работает. Я также проверил зависимости, и моя dll зависит от epanet.dll. – Alberto

0

http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html

I don't know how do get long* in mydll because string -> jstring or int -> jint but long* -> ??? or int* -> ???? that long* -> jlongArray (and int* ->jintArray)

пример: принять длинный [] в Java декларации родной метод в JNI вы увидите jlongArray в этой позиции аргумента. конвертировать jlongArray в jlong ​​* с помощью GetDoubleArrayElements() (см. ссылку для doc), а jlong ​​- 64 бит (http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html), вы можете использовать его.
же для булева, межд, Java объект (см документации для вариаций) ....


прежде чем первое обновление Exception in thread "main" java.lang.UnsatisfiedLinkError: NewClass.epanet(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String)V я предполагаю, что вы сделали ошибку где-то в составлении и/или управлениях

public class NewClass { 
    private native void ENopen(String f1, String f2, String f3); 

причина: ошибка должна быть

java.lang.UnsatisfiedLinkError: NewClass. ENopen (Ljava/языки/String; Ljava/языки/String; Ljava/языки/String) V

их не имя метода "NewClass.epanet" в вас источник (даже после обновления).

Смежные вопросы