【CSDN常見問題解答】使用JNA調用Windows動態庫

Java中調用Windows平臺的動態庫一般會使用JNI(Java Native Interface)還有JNA(Java Native Access)。

首先解釋下爲什麼我會選用JNA,一句話來說就是使用簡單。

我們知道,使用JNI調用.dll/.so共享類庫是非常非常麻煩和痛苦的。 如果有一個現有的.dll/.so文件,如果使用JNI技術調用,我們首先需要另外使用C語言寫一個.dll/.so共享庫,使用SUN規定的數據結構替代C語言的數據結構,調用已有的 dll/so中公佈的函數。然後再在Java中載入這個適配器dll/so,再編寫Java  native函數作爲dll中函數的代理。

經過2個繁瑣的步驟才能在Java中調用本地代碼。因此,很少有Java程序員願意編寫調用dll/.so庫中的原生函數的java程序。這也使Java語言在客戶端上乏善可陳。可以說JNI是Java的一大弱點!所以我們就選擇JNA來寫幾個簡單的demo。

JNA在GitHub上的地址:https://github.com/twall/jna

需要jar包,到lib文件夾裏面去下載。

下面我們開始使用JNA。

第一個例子:

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;

public class HelloWorld {
	public interface CLibrary extends Library {
		CLibrary INSTANCE = (CLibrary) Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);
		void printf(String format, Object... args);
	}

	public static void main(String[] args) {
		CLibrary.INSTANCE.printf("Hello World, ");
		for (int i = 0; i < args.length; i++) {
			CLibrary.INSTANCE.printf("Argument %d: %s, ", i, args[i]);
		}
	}
}

運行上面的代碼,我給main函數傳遞了3個參數1 2 3,打印如下:

Hello World, Argument 0: 1, Argument 1: 2, Argument 2: 3, 

但是,請注意,這個程序實際上是使用msvcrt.dll這個C運行時庫中的printf函數打印出上面這些字符的。是不是很簡單,不需要寫一行C代碼,就可以直接在Java中調用外部動態鏈接庫中的函數!

 

第二個例子:

上面那個例子使用了操作系統自帶的動態鏈接庫,現在我們再自己寫一個動態鏈接庫試試。

1,在VS中選擇C++語言,然後選擇創建一個Win32程序。選擇dll類型。
2,發佈的C函數是:


#define MYLIBAPI extern  "C"    __declspec(dllexport ) 
MYLIBAPIvoid say(wchar_t* pValue);

這個函數的實現是:

void say(wchar_t* pValue){
    std::wcout.imbue(std::locale("chs"));
    std::wcout<<L"他說:"<<pValue<<std::endl;
}

它需要傳入一個Unicode編碼的字符數組。然後在控制檯上打印出一段中文字符。
3,生成dll(TestDll1.dll)。然後把生成的dll文件複製到Eclipse項目中,放在項目下面。

4,然後編寫下面的類:

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.WString;

public class TestDll1Service {

        public interface TestDll1 extends Library {
                  /**

                   * 當前路徑是在項目下,而不是bin輸出目錄下。

                   */

                  TestDll1 INSTANCE = (TestDll1)Native.loadLibrary("TestDll1", TestDll1.class);
                  public void say(WString value);

        }

        public TestDll1Service() {

        }

 

        /**

         * @param args

         */

        public static void main(String[] args) {
                  TestDll1.INSTANCE.say(new WString("Hello World!"));
                  System.out.println("你好,我是來測試的!");
        }

}

5,執行這個Java類。可以看到控制檯下如下輸出:

他說: Hello World!

你好,我是來測試的!

6,上面一行是C語言使用C++的std::wcout輸出的。 下面一行是Java語言輸出的。





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