Проблема JNI: вызов в Java DLL, которая использует стороннюю DLL - PullRequest
1 голос
/ 21 ноября 2010

Я хочу использовать epanet.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");
   }
}

Затем Джава создал de .hfile

/* 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, который должен вызывать 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;
}

и затем компилироваться.Visual C ++ создает мою 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");
     }
}

Тогда моя 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 =  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 *);

Я не знаю, как получить long * в mydll, потому что строка -> jstring или int -> jint, но long* ->?или int * ->?

Ответы [ 4 ]

0 голосов
/ 22 октября 2014

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

Я не знаю, как получить long * в mydll, потому что строка -> jstring или int -> jint, но long * -> ??? или int * -> ???? that long * -> jlongArray (и int * -> jintArray)

Пример: примите long [] в объявлении нативного метода java, в jni вы увидите jlongArray в этой позиции аргумента. конвертируйте jlongArray в jlong ​​*, используя GetDoubleArrayElements () (см. ссылку на документацию), и jlong ​​равен 64 битам (http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html),, вы можете использовать его.
то же самое для логического, int, 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 / lang / String; Ljava / lang / String; Ljava / lang / String) V

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

0 голосов
/ 22 ноября 2010

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

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

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

0 голосов
/ 22 ноября 2010

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

0 голосов
/ 21 ноября 2010

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

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

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

...