天天看點

JNI技術實踐小結

JNI 技術實踐小結

       昨天和一部zzz一起研究解決一個 java 調用第三方 dll 的問題,從零開始學習了 jni 技術的應用,現在總結如下。

       事情的起因是一部的一個項目需要用到一個愛國者提供的基于 U 盤的加密技術。對方提供了 U 盤和一個 dll 動态連結庫 hiddenIO.dll 。在 U 盤的隐藏區域内可以儲存 USB-Key 資訊,通過這個 dll 裡的兩個方法可以使用 c/c++ 編寫程式在 U 盤的隐藏區域讀寫資訊,對方提供了示例代碼。由于一部的項目是基于 SWT/RCP 技術的,是以需要在 java 程式中調用這兩個方法。

       目前 java 與 dll 互動的技術主要有 3 種: jni , jawin 和 jacob 。 Jni ( Java Native Interface )是 sun 提供的 java 與系統中的原生方法互動的技術(在 windows\linux 系統中,實作 java 與 native method 互調)。目前隻能由 c/c++ 實作。後兩個都是 sourceforge 上的開源項目,同時也都是基于 jni 技術的 windows 系統上的一個應用庫。 Jacob ( Java-Com Bridge )提供了 java 程式調用 microsoft 的 com 對象中的方法的能力。而除了 com 對象外, jawin ( Java/Win32 integration project )還可以 win32-dll 動态連結庫中的方法。就功能而言: jni >> jawin>jacob ,其大緻的結構如下圖:

JNI技術實踐小結

jni 技術體系功能結構圖

就易用性而言,正好相反: jacob>jawin>>jni 。

Jvm 封裝了各種作業系統實際的差異性的同時,提供了 jni 技術,使得開發者可以通過 java 程式(代碼)調用到作業系統相關的技術實作的庫函數,進而與其他技術和系統互動,使用其他技術實作的系統的功能;同時其他技術和系統也可以通過 jni 提供的相應原生接口開調用 java 應用系統内部實作的功能。

在 windows 系統上,一般可執行的應用程式都是基于 native 的 PE 結構, windows 上的 jvm 也是基于 native 結構實作的。 Java 應用體系都是建構于 jvm 之上。

JNI技術實踐小結

Windows 系統上的 java 體系

Jni 對于應用本身來說,可以看做一個代理模式。對于開發者來說,需要使用 c/c++ 來實作一個代理程式( jni 程式)來實際操作目标原生函數, java 程式中則是 jvm 通過加載并調用此 jni 程式來間接地調用目标原生函數。

JNI技術實踐小結

Jni 調用過程示意圖

Jni 程式開發的一般操作步驟如下:

1.   編寫 java 中的調用類

2.用 javah 生成 c/c++ 原生函數的頭檔案

3. c/c++ 中調用需要的其他函數功能,實作原生函數 ( 原則上可以調用任何資源 )

4. 将項目依賴的所有原生庫和資源加入到 java 項目的 java.library.path

5. 生成 java 程式

6. 釋出 java 應用和 dll 庫

Jni 程式開發示例:

1.在 eclipse 項目中建立一個 TestHello.java ,輸入以下内容:

public class TestHello { 

  static {

     System.loadLibrary("TestHello");

  } 

  public static native void hello(String msg); 

  public static void main(String[] args) {    

     hello("Hello,Kimm!");    

  } 

}
           

編譯生成 TestHello. class 檔案。

2. 在指令行下使用 javah TestHello 指令,生成 TestHello.h 頭檔案(就是 jni 代理 stub 的接口)。

3. 在 VC6 中建立一個項目 TestHello, 項目類型為 Win32 Dynamic-Link Library 。點選 OK 。

JNI技術實踐小結

在彈出的視窗中選擇 A simple DLL project ,點選 Finish 。

JNI技術實踐小結

打開項目所在的檔案目錄,将步驟 2 中生成的 TestHello.h 檔案複制到此目錄。點選左邊中間的 FileView ,切換到檔案浏覽模式。在 Header Files 上點選右鍵,選擇 Add Files to Folder… 。

選擇 TestHello.h 檔案,點選 OK 。

JNI技術實踐小結

打開 StdAfx.h 檔案,再最後面添加:

#include <jni.h>

#include "TestHello.h"

JNI技術實踐小結

打開 TestHello.cpp 檔案,在最後面添加一段代碼:

JNIEXPORT void JNICALL Java_TestHello_hello(JNIEnv * env, jclass obj, jstring jMsg){
    const char *strMsgPtr = env->GetStringUTFChars( jMsg , 0);  
       MessageBox( 0, strMsgPtr,"Message box from VC++ ", 0 );
       env->ReleaseStringUTFChars( jMsg, strMsgPtr); 
}
           

在 VC 的菜單上選擇 Tools-Options… ,打開選項對話框。在 Directories 檔案夾,添加上 jdk 所在檔案夾下的 include 和 include\win32 檔案夾。

JNI技術實踐小結

點選 VC 上的菜單項 Build-Build All ,生成 TestHello.dll 。

4.将 VC 項目 Debug 檔案夾中的 TestHello.dll 複制到 TestHello.class 所在的檔案夾下。

5. 在指令行下輸入 java TestHello ,彈出 MessageBox 對話框。調用 win32 api 成功。

JNI技術實踐小結

樓主寫的不錯,我安樓主寫的走了一篇,對jni有了初步的了解,謝謝樓主。

我的用的VS 2005以下是我走的過程中,碰到的問題我解決的方法。希望對其他vs不熟的人有點幫助:

問題 1 : fatal error C1083: 無法打開包括檔案L ..........  No such file or directory

解決:“項目--->屬性---->配置屬性---->C/C++---->正常---->附加包含目錄”選項中有很多include下的庫

問題 2: error C2664: “MessageBoxW”: 不能将參數 2 從“const char *”轉換為“LPCWSTR”

解決:所說字元集問題,我的vs2003這樣設: 項目屬性-> 配制屬性-> 正常-> 字元集-> 選:使用多位元組字元集

問題 3:沒有找到MSVCR80D.dll,是以這個應用程式未能啟動。

找到你的工程的檔案夾,如(myproject),找到其下的myproject\myproject\Debug\ myproject.rec,把它删掉(删掉整個Debug目錄也可以),重新編譯,搞定!

:lol: