標籤:jnienv 導致 動態 include 產生 env int stdio.h char
研究發現, 無論是使用gcc還是g++, GCC for Windows產生DLL動態連結程式庫時都會修改我們的符號, 導致即使載入了動態連結程式庫, JVM仍然找不到符號, 從而產生java.lang.UnsatisfiedLinkError錯誤
所以還是使用微軟自家的VS來產生DLL比較妥當, 由於VS命令列錯綜複雜, 建議使用圖形介面, 下面是配置要點.
(1) 包含jdk目錄下的include和include\win32目錄, 便於尋找jni.h和jni_md.h
(2) 如使用純C代碼, 則包含jni.h前插入代碼 #undef __cplusplus 可使代碼提示更友好.
配置好後, 我們來實現一個Java native方法.
package pkg;public class WinMessageBox {/** * 彈出一個全域對話方塊 * @param label 視窗標題 * @param content 表單內容 * @return 調用結果 */public static native boolean showMessageBox(String label, String content);}
使用javah.exe來產生一個聲明了WinMessageBox類中需要實現的native方法的標頭檔
javah pkg.WinMessageBox
得到檔案pkg_WinMessageBox.h, 使用VS實現它.
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class pkg_WinMessageBox */#ifndef _Included_pkg_WinMessageBox#define _Included_pkg_WinMessageBox#ifdef __cplusplusextern "C" {#endif/* * Class: pkg_WinMessageBox * Method: showMessageBox * Signature: (Ljava/lang/String;Ljava/lang/String;)V */JNIEXPORT jboolean JNICALL Java_pkg_WinMessageBox_showMessageBox (JNIEnv *, jclass, jstring, jstring);#ifdef __cplusplus}#endif#endif
#undef __cplusplus#include "H:\Code\EclipseWorkSpace\TEST\bin\pkg_WinMessageBox.h"#include <Windows.h>#include <stdlib.h>#include <stdio.h>#include <time.h>JNIEXPORT jboolean JNICALL Java_pkg_WinMessageBox_showMessageBox(JNIEnv *env, jclass clazz, jstring label, jstring content){MessageBoxW((HWND) NULL, (LPCWSTR) (**env).GetStringChars(env, content, 0), (LPCWSTR) (**env).GetStringChars(env, label, 0), MB_OK);srand((UINT) time(0));return rand() % 2 > 0 ? TRUE : FALSE;}
產生項目後, 編寫測試
在這個過程中我們發現, 雖然我們需要使用動態連結程式庫JVM.dll中的函數, 但是我們並不需要顯式地去連結它, 這是因為我們的對JVM函數的調用都是使用形參中傳入的JNIEnv指標指向的結構體對象指標指向的結構體對象中的一張函數指標表調用的, Java運行時會為我們打包JVM上下文, 並將這張表填好, 在調用本地方法時將其作為參數傳入, 這樣一來我們就可以在本地方法中使用表中的指標調用函數了.
[Java JNI] [Windows] [Visual Studio] [DLL] [UnsatisfiedLinkError]