最近一直在編寫各類硬件產品接口的工做,什麼刷卡機,打印機,掃描儀,刻錄機,其中好可能是基於C++來開發,對與我來講,仍是java比較順手,因而考慮採用jni的方式來作,jni的名號,我如雷貫耳已經7,8年了,一直未真正的和他有過接觸,下面把最近的一些心得總結出來。下面以我編寫刻錄機程序爲例子:java
編寫java類ios
- package com.xk.burn;
- import java.io.InputStream;
- import org.apache.log4j.Logger;
- import com.xk.scanner.Scanner;
- public class Recorder
- {
- private static Logger logger = Logger.getLogger(Recorder.class);
- public native void burn(InputStream is);
- static
- {
- try
- {
- System.loadLibrary("xk-burn");
- }
- catch (Exception ex)
- {
- logger.error("", ex);
- }
- logger.info("load library : xk-burn sucessful!");
- }
- }
咱們要調用的dll名稱是xk-burn。c++
下面咱們使用javah命令來生成c++的頭文件。 打開cmd窗口,進入到編譯java類生成class的目錄下。執行javah com.xk.burn.Recorder 而後到這個目錄下,會發現com_xk_burn_Recorder.h這個文件。下面咱們打開vs2010,新建一個win32工程,而後選擇dll,而且勾選空項目。而後將頭文件添加進去。而後在源文件下,新建xk-burn.cpp, 代碼以下:apache
- #include <iostream>
- #include "com_xk_burn_Recorder.h"
- JNIEXPORT void JNICALL Java_com_xk_burn_Recorder_burn(JNIEnv env, jobject jobj, jobject inputStream)
- {
- std::cout << inputStream << std::endl;
- }
這裏有要注意的地方。新生成的頭文件的內容爲:ide
- /* DO NOT EDIT THIS FILE - it is machine generated */
- #include <jni.h>
- /* Header for class com_xk_burn_Recorder */
- #ifndef _Included_com_xk_burn_Recorder
- #define _Included_com_xk_burn_Recorder
- #ifdef __cplusplus
- extern "C" {
- #endif
- /*
- * Class: com_xk_burn_Recorder
- * Method: burn
- * Signature: (Ljava/io/InputStream;)V
- */
- JNIEXPORT void JNICALL Java_com_xk_burn_Recorder_burn(JNIEnv *, jobject, jobject);
- #ifdef __cplusplus
- }
- #endif
- #endif
參數部分能夠看到,並無實際的變量定義,只有類型。咱們必須將頭文件的方法,與實現部分的方法保證一致。 上面兩段代碼很顯然,並不一致,頭文件中無參數變量,而實現中定義了明確參量變量(JNIEnv env, jobject jobj, jobject inputStream)若是咱們就以目前的狀態編譯,而後將生成的dll,放在java工程的最外層目錄下,編寫測試類調用下試試,測試類以下:測試
- package com.xk.burn;
- import org.apache.commons.io.IOUtils;
- import com.xk.core.Initialization;
- public class RecorderTestCase
- {
- public static void main(String args[]) throws Exception
- {
- Initialization.getInitialization();
- Recorder recorder = new Recorder();
- recorder.burn(IOUtils.toInputStream("test jni"));
- System.exit(0);
- }
- }
就會拋出下面異常信息:Exception in thread "main" java.lang.UnsatisfiedLinkError: com.xk.burn.Recorder.burn(Ljava/io/InputStream;)V,這是什麼緣由呢,就是由於頭文件和實現的參數部分不匹配,咱們能夠用dll 導出查看器查看一下,vc2010有dumpbin命令 咱們在命令行下執行 dumpbin /exports xk-burn.dll 就能夠看出,dump出心中,dll的方法名稱被篡改了,因此咱們的測試沒法調用到方法。因此頭文件應該修改成:spa
- /* DO NOT EDIT THIS FILE - it is machine generated */
- #include <jni.h>
- /* Header for class com_xk_burn_Recorder */
- #ifndef _Included_com_xk_burn_Recorder
- #define _Included_com_xk_burn_Recorder
- #ifdef __cplusplus
- extern "C" {
- #endif
- /*
- * Class: com_xk_burn_Recorder
- * Method: burn
- * Signature: (Ljava/io/InputStream;)V
- */
- JNIEXPORT void JNICALL Java_com_xk_burn_Recorder_burn(JNIEnv env, jobject jobj, jobject inputStream);
- #ifdef __cplusplus
- }
- #endif
- #endif
再從新編譯爲dll,將編譯出的dll覆蓋剛纔java程序使用的dll,而後從新執行測試用例獲得下面結果:命令行
INFO: 2012-05-10 10:56:08,616 -- com.xk.burn.Recorder -- load library : xk-burn sucessful!
0092FCCC接口
至此,咱們的jni的使用大功告成,能夠在實現中添加我得控制刻錄機的程序代碼了。開發