jni使用總結

最近一直在編寫各類硬件產品接口的工做,什麼刷卡機,打印機,掃描儀,刻錄機,其中好可能是基於C++來開發,對與我來講,仍是java比較順手,因而考慮採用jni的方式來作,jni的名號,我如雷貫耳已經7,8年了,一直未真正的和他有過接觸,下面把最近的一些心得總結出來。下面以我編寫刻錄機程序爲例子:java

編寫java類ios

  
  
  
  
  1. package com.xk.burn;  
  2.  
  3. import java.io.InputStream;  
  4. import org.apache.log4j.Logger;  
  5. import com.xk.scanner.Scanner;  
  6.  
  7. public class Recorder  
  8. {  
  9.     private static Logger logger = Logger.getLogger(Recorder.class);  
  10.       
  11.     public native void burn(InputStream is);  
  12.       
  13.     static 
  14.     {  
  15.         try 
  16.         {  
  17.             System.loadLibrary("xk-burn");  
  18.         }  
  19.         catch (Exception ex)  
  20.         {  
  21.             logger.error("", ex);  
  22.         }  
  23.         logger.info("load library : xk-burn sucessful!");  
  24.     }  

咱們要調用的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

  
  
  
  
  1. #include <iostream>  
  2. #include "com_xk_burn_Recorder.h"  
  3.  
  4. JNIEXPORT void JNICALL Java_com_xk_burn_Recorder_burn(JNIEnv env, jobject jobj, jobject inputStream)  
  5. {  
  6.     std::cout << inputStream << std::endl;       

 這裏有要注意的地方。新生成的頭文件的內容爲:ide

  
  
  
  
  1. /* DO NOT EDIT THIS FILE - it is machine generated */ 
  2. #include <jni.h>  
  3. /* Header for class com_xk_burn_Recorder */ 
  4.  
  5. #ifndef _Included_com_xk_burn_Recorder  
  6. #define _Included_com_xk_burn_Recorder  
  7. #ifdef __cplusplus  
  8. extern "C" {  
  9. #endif  
  10. /*  
  11.  * Class:     com_xk_burn_Recorder  
  12.  * Method:    burn  
  13.  * Signature: (Ljava/io/InputStream;)V  
  14.  */ 
  15. JNIEXPORT void JNICALL Java_com_xk_burn_Recorder_burn(JNIEnv *, jobject, jobject);  
  16.  
  17. #ifdef __cplusplus  
  18. }  
  19. #endif  
  20. #endif  

 參數部分能夠看到,並無實際的變量定義,只有類型。咱們必須將頭文件的方法,與實現部分的方法保證一致。 上面兩段代碼很顯然,並不一致,頭文件中無參數變量,而實現中定義了明確參量變量(JNIEnv env, jobject jobj, jobject inputStream)若是咱們就以目前的狀態編譯,而後將生成的dll,放在java工程的最外層目錄下,編寫測試類調用下試試,測試類以下:測試

  
  
  
  
  1. package com.xk.burn;  
  2.  
  3. import org.apache.commons.io.IOUtils;  
  4.  
  5. import com.xk.core.Initialization;  
  6.  
  7. public class RecorderTestCase  
  8. {  
  9.     public static void main(String args[]) throws Exception  
  10.     {  
  11.         Initialization.getInitialization();  
  12.         Recorder recorder = new Recorder();  
  13.         recorder.burn(IOUtils.toInputStream("test jni"));  
  14.           
  15.         System.exit(0);  
  16.     }  
  17. }  

就會拋出下面異常信息: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

  
  
  
  
  1. /* DO NOT EDIT THIS FILE - it is machine generated */ 
  2. #include <jni.h>  
  3. /* Header for class com_xk_burn_Recorder */ 
  4.  
  5. #ifndef _Included_com_xk_burn_Recorder  
  6. #define _Included_com_xk_burn_Recorder  
  7. #ifdef __cplusplus  
  8. extern "C" {  
  9. #endif  
  10. /*  
  11.  * Class:     com_xk_burn_Recorder  
  12.  * Method:    burn  
  13.  * Signature: (Ljava/io/InputStream;)V  
  14.  */ 
  15. JNIEXPORT void JNICALL Java_com_xk_burn_Recorder_burn(JNIEnv env, jobject jobj, jobject inputStream);  
  16.  
  17. #ifdef __cplusplus  
  18. }  
  19. #endif  
  20. #endif 

再從新編譯爲dll,將編譯出的dll覆蓋剛纔java程序使用的dll,而後從新執行測試用例獲得下面結果:命令行

INFO: 2012-05-10 10:56:08,616 -- com.xk.burn.Recorder -- load library : xk-burn sucessful!
0092FCCC
接口

至此,咱們的jni的使用大功告成,能夠在實現中添加我得控制刻錄機的程序代碼了。開發

相關文章
相關標籤/搜索