簡體   English   中英

JNI問題:在Java中調用使用第三方dll的Dll

[英]JNI issue: calling in Java a Dll that uses a third party dll

我想使用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");
   }
}

然后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

然后,我創建了應調用epanet2 dll的.c文件

#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。 然后,我嘗試使用我的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(第三方1)。

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 *);

我不知道如何在mydll中獲取long *,因為string-> jstring或int-> jint但long *->嗎? 還是int *->?

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

我不知道如何在mydll中獲取long *,因為string-> jstring或int-> jint但long *-> ??? 或int *-> ???? 那長*-> jlong​​Array(和int *-> JintArray)

示例:在Java本機方法聲明中接受long [],在jni中,您將在該參數位置看到jlong​​Array。 使用GetDoubleArrayElements()將jlong​​Array轉換為jlong​​ *(請參閱文檔鏈接),並且jlong​​是64位( http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html ),您可以使用它。
對於boolean,int,java對象也一樣(有關變化請參見文檔)。


在您第一次更新Exception in thread "main" java.lang.UnsatisfiedLinkError: NewClass.epanet(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String)V之前, 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”(即使更新后)。

我的兩分錢:

包裝DLL包含Epanet類中本機方法的實現,而不是測試代碼中正在調用的本機方法的實現(請注意stacktrace中的類名)。 我認為您應該使用new Epanet().ENopen( "C:\\\\Red2.inp", "C:\\\\salaida.txt", "" ); 代替。

另外,用於Epanet的靜態初始化Epanet應加載您的DLL,而不是包裝的庫(如果包裝是正確構建的,操作系統將進行處理)。

您提供了兩個Java類和僅一個本機實現的源。 這確實使我們難以理解。 擺脫NewClass。

您希望您的Epanet Java類在System.loadLibrary()調用中加載其本機包裝,然后包裝dll將自動加載epanet.dll。

就將long *傳遞到本機代碼而言,您不能這樣做。 創建java-c包裝器類的技能在於,您不能直接調用原始方法! 您可以輸入簡單的long,但是對long所做的任何更改都將丟失。 因此,您可以將可變的Java對象傳遞給包裝器調用並對其進行更改,或者更簡單地讓本機方法更改Epanet類的某些狀態。

我建議嘗試Dependency Walker來查看是否還需要其他DLL(例如,您可能缺少Microsoft C運行時)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM