最近做項目使用JNI引用C++的dll,在此記錄遇到的問題。
1.如何導出C++中的類
大家都知道JNI只能導出全局函數,至少我搜索了好久都沒看到過有導出類的,貌似不可以。當然如果可以就更好了。
那麼既然使用的是C++語言,如果不使用類的話,那還不如直接使用C。總之,面向對象編程就是比面向過程”藝術”。所以就遇到個問題,C++類中的成員函數如何使用JNI導出?JNI只能導出全局函數。
所以,我們可以採用一個折中的辦法,爲每一個類成員函數寫一個全局導出函數,在cpp實現文件中new 一個類對象,在全局函數中使用這個類對象調用成員函數,最後寫一個全局函數釋放這個類對象。
例如:
//Dog.h
class Dog()
{
public:
Dog();
~Dog();
void eat(){std::cout<<"eat bone\n";};
...
}
要想通過JNI導出Dog類的eat成員函數,當然可以有多個成員函數,我們新建一個文件:
//export.h
#include "jni.h"
extern "C"
{
JNIEXPORT void JNICALL JAVA_com_wj_demo_init(JNIEnv *env, jobject);
JNIEXPORT void JNICALL JAVA_com_wj_demo_eat(JNIEnv *env, jobject);
JNIEXPORT void JNICALL JAVA_com_wj_demo_release(JNIEnv *env, jobject);
}
因爲成員函數必須使用類的實例調用,所以我們可以在export.cpp中實例化這個類:
//export.cpp
#include "Dog.h"
Dog *dog ;
JNIEXPORT void JNICALL JAVA_com_wj_demo_init(JNIEnv *env, jobject)
{
dog = new Dog();
}
JNIEXPORT void JNICALL JAVA_com_wj_demo_eat(JNIEnv *env, jobject)
{
dog->eat();
}
JNIEXPORT void JNICALL JAVA_com_wj_demo_release(JNIEnv *env, jobject)
{
dog->~Dog();
}
這樣大概就可以了。手寫的代碼,不保證能運行,但是就是這思路。
2.在java中System.loadLibrary()注意的問題
<1>如果是64爲的jdk必須加載64位的dll,debug版本的和release版本的都沒關係,可以相互調用,但是必須是64位的。
<2>必須先加載依賴庫,比如你要引用的a.dll還引用着b.dll,就必須先使用System.loadLibrary加載b.dll,再加載a.dll,有時候一個dll依賴多個dll的時候,需要注意加載的順序。
<3>有些64位的dll引用的竟然是32位的dll,竟然也能編譯過了。比如,我的項目中引用libcurl.dll,再loadLibrary的時候,報 %1 libcurl不是win32應用程序,我就納悶了。然後在dependency工具下看到其引用的SSLEAY32.dll和LIBEAY32.dll竟然是32位的,估計是系統目錄下的,因爲我引用的dll目錄中沒有這兩個dll,如果沒有找的話,編譯Java程序的時候會報找不到依賴庫,但是沒報這個錯,說明是在系統目錄下找到的。所以,我找到了SSLEAY32.dll和LIBEAY32.dll這兩個的64位版本的,就可以了。