JNI引用C++dll若干問題總結-如何導出C++中的類成員函數

最近做項目使用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位版本的,就可以了。

發佈了98 篇原創文章 · 獲贊 68 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章