2010-11-21 121 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 

然後我創建的應該叫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(第三方之一)。

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因爲字符串 - >的jstring或者int - > jint但長* - >?或者int * - >?

+0

你有檢查,你沒有錯誤的DLL躺在你的bin文件夾? – dacwe 2010-11-21 12:33:44

+0

爲什麼你有兩個'loadLibrary(..)'調用?你只有一個界面! – dacwe 2010-11-21 12:37:43

+0

我不知道如何檢查是否有錯誤的DLL。一切正常。 – Alberto 2010-11-21 16:59:31

回答

0

我的兩分錢:

的包裝DLL包含了本地方法的實現在你Epanet類,而不是本地方法你在你的測試代碼(注意堆棧跟蹤類名)調用。我想你應該使用new Epanet().ENopen("C:\\Red2.inp", "C:\\salaida.txt", "");來代替。

此外,Epanet的靜態初始化程序應該加載您的DLL,而不是包裝的庫(如果您的包裝程序構建正確,操作系統會照顧它)。

+0

我已經改變了通話到新的Epanet()。ENopen(......),現在我得到了一個錯誤。在這個工作一週後,這真是太棒了:D – Alberto 2010-11-21 21:08:56

+0

第二個評論你說我不知道​​如何解決它。在這個是有限的,因爲沒有適合我的dll的教程/演示 – Alberto 2010-11-21 21:09:33

0

您已經提供了兩個Java類的源,並且只提供了一個本地實現。這會讓我們更難理解。擺脫NewClass。

你想讓你的Epanet Java類在System.loadLibrary()調用中加載它的本機包裝,然後你的包裝DLL將自動加載epanet.dll。

在傳遞一個長*到你的本地代碼方面,你不能。創建java-c包裝類的技巧是你不能直接調用原始方法!你可以通過一個簡單的長時間,但隨後對長期所做的任何更改都將丟失。所以你可以將一個可變的java對象傳遞給你的包裝調用,並且改變它或者更簡單地使本地方法改變Epanet類的某些狀態。

+0

請檢查我發佈的新解決方案 – Alberto 2010-11-21 22:03:53

+0

關於第二個評論,我想我理解你我的Java類將傳遞給我的dll只要jlong​​。然後,我在mydll中創建一個long var,將它複製到jlong​​中,我用&long調用本地方法。正如你所說,當我的dll返回時,我將失去對long var的所有修改。 – Alberto 2010-11-21 22:08:27

0

我建議您嘗試Dependency Walker以查看是否有其他可能需要的DLL(例如,您可能會錯過Microsoft C運行時)。

+0

T這裏有個問題。我從頭開始重建了所有東西,並且工作正常。我也檢查了依賴關係,我的DLL依賴於epanet.dll。 – Alberto 2010-11-22 19:55:48

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,你會看到在jlong​​Array這樣的說法位置。使用GetDoubleArrayElements()將jlong​​Array轉換爲jlong​​ *(請參閱doc的鏈接),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。 (即使在更新之後),它們並不是方法名稱「NewClass.epanet」。這個方法名稱爲「NewClass.epanet」。