jni使用总结

最近一直在编写各种硬件产品接口的工作,什么刷卡机,打印机,扫描仪,刻录机,其中好多是基于C++来开发,对与我来说,还是java比较顺手,于是考虑采用jni的方式来做,jni的名号,我如雷贯耳已经7,8年了,一直未真正的和他有过接触,下面把最近的一些心得总结出来。下面以我编写刻录机程序为例子:

编写java类

  
  
  
  
  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。

下面我们使用javah命令来生成c++的头文件。 打开cmd窗口,进入到编译java类生成class的目录下。执行javah com.xk.burn.Recorder 然后到这个目录下,会发现com_xk_burn_Recorder.h这个文件。下面我们打开vs2010,新建一个win32工程,然后选择dll,并且勾选空项目。然后将头文件添加进去。然后在源文件下,新建xk-burn.cpp, 代码如下:

  
  
  
  
  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;       

 这里有要注意的地方。新生成的头文件的内容为:

  
  
  
  
  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的方法名称被篡改了,所以我们的测试无法调用到方法。所以头文件应该修改为:

  
  
  
  
  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的使用大功告成,可以在实现中添加我得控制刻录机的程序代码了。

本文出自 “My Joy is my joy ~” 博客,转载请与作者联系!

你可能感兴趣的:(jni)