`

(转)JNA的使用经历

阅读更多

最尽项目中应用到在Java中调用C/C++的DLL,其中的应用经历记录下来,顺便总结一下思考的过程,文中不会过多的说明基本的JNA调用实现。
相关知识可以参考:https://jna.dev.java.net/
建议在使用之前好好看一下,这样可以少走很多的弯路。。。

应用背景:
 移动充值项目中需要用一个DES的加密算法,而这个算法又不是标准的,客户那边提供过来一个用C++写的原程序,而我们的系统是用Java实 现的,所以必需要进行转换,才能够使用。


解决办法:

要想在Java中使用该DES算法有以下几种方法:
1、将C++代码转化成Java代码;
2、将C++的原代码封装成DLL,然后在Java中调用;

由于加密算法相当复杂,有相当多的指针运算、位运算等等,要想把它改造成Java程序,困难重重,简单尝试之后,就放弃了该方法,转而将其封装成DLL, 在Java中调用;

在Java中调用C++的DLL也有两种方法:
1、通过JNI实现调用;
2、通过JNA实现调用;

“不堪回首的JNI
我们知道,使用JNI调用.dll共享类库是非常非常麻烦和痛苦的。
如果有一个现有的.dll文件,如果使用JNI技术调用,我们首先需要另外使用C++语言写一个.dll共享库,使用SUN规定的数据结构替代C++语言 的数据结构,调用已有的  dll中公布的函数。然后再在Java中载入这个适配器dll,再编写Java   native函数作为dll中函数的代理。经过2个繁琐的步骤才能在Java中调用本地代码。”

以上是在网络上找到的对JNI的评价,而JNA就相对好用很多,只是有一个JNA的JAR包,然后对应申明DLL中应用的函数,然后在Java中就可以使 用了。


实现步骤:  
1、首先找一个C++的编译器,将其编译成DLL,选用的工具是MircroSoft Visual C++(原因是客户入指供的C++原码中有MFC相关的内容,使用Borland C++Build编译无法通过),对外输出要使用的函数(方法),本实例中应用到的函数如下:

// 输出缓冲区(Out)的长度 >= ((datalen+7)/8)*8,即比datalen大的且是8的倍数的最小正整数
// 当keylen>8时系统自动使用3次DES加/解密,否则使用标准DES加/解密.超过16字节后只取前16字节
bool Des_Go(char *Out, char *In, long datalen, const char *Key, int keylen, bool bType);

2、在Java中写对应的DES_Go函数:
 这里花费了较长的时间,主要是类型对应上,对于C中的 "Char *"在JNA中可以用String与之对应,但由于char *Out是要输出的数据,在C/C++中是分配了一段内存地址,然后用指针指向其对应的首地址; 以下是几种尝试方式:

a、用String来对应C++中"Char *":
Boolean Des_Go(String Out, String In, int datalen, final String Key, int keylen, Boolean bType);
在Java中调用不报错,但取不到Out中的值,首先怀疑是DLL有问题,于是用Delphi写了一个应用该DLL的小程序(由于Delphi调用DLL 相对比较简单,而且Delphi中有PChar可以与"Char *"对应),测试下来成功,故排处DLL有问题的想法,后来想原因可能是这样的,Java将基本数据类型都放在栈中,其分配的大小是固定的,当超过变量的 作用域后,Java会自动释放掉为该变量所分配的内存空间,所以取不到值。

 

b、用PointerByReference来对应C++中"Char *":
Boolean Des_Go(PointerByReference Out, String In, int datalen, final String Key, int keylen,
        Boolean bType);
在JNA中就是用PointerByReference  来对应C/C++中的指针(后来才知道对应的是Char **,但也是可以使用的,只是在取值时要用getPointer(),而不能用getValue(),用后者调用会报:Invalid memory access),但在Java中通过该方式调用时,不稳定时有报错,加密是成功了,但同时加密后的结果,用来解密时还原不出来之前的结果,感觉很困惑,估 计还是类型上的问题,加密之后显示的是乱码,然后对这些乱码进行解密就无法返回原来的值。(原因:由于一些ASCII码在字符串无法显示出来,如控制字符 等等,所以用这样的字符串进行解密,十有八九是无法还原的)。考虑既然字符串会显示乱码,那是否可以用字节数组呢,这样就可以屏蔽这个问题。

 

c、用byte[]来对应C++中"Char *":
Boolean Des_Go(byte[] Out, byte[] In, int datalen, final byte[] Key, int keylen, Boolean bType);

实验下来,终于得到自己想要的结果,“山穷水尽疑无路,柳岸花明又一村。”那个兴奋啊。。。

 

附上Java中JNA的使用原码,通过这个源码可以看出用JNA的方式调用C/C++的DLL是多么的简单、方便。

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

public class DESUtil {
  private static DESLibrary NATIVE;

  static {
    try {
       Native.setProtected(true);
       NATIVE = (DESLibrary) Native.loadLibrary("DES", DESLibrary.class);
    } catch (UnsatisfiedLinkError e) {
       System.out.println("DES not found");
    }
  }
}
 

 

public interface DESLibrary extends Library {
     Boolean Des_Go(byte[] Out, byte[] In, int datalen, final byte[] Key, int keylen, Boolean bType);
}
 
public static void main(String[] args) {
    DESUtil.NATIVE.Des_Go(.......)
}
分享到:
评论

相关推荐

    C++头文件转JAVA JNA接口类

    一个将C++头文件转JAVA JNA接口类的工具类,方便java程序调用C++ DLL的接口

    JNA使用详解,包括jna.jar 和一个完整的JNA例子

    该资源中,包含jna.jar 和一个jna的函数文档。并且有一个完整的使用例子。该例子是访问本地的IC卡读卡器,其中因为原始厂商提供的本地代码函数过于发杂,为了便于JNA调用,又对本地代码...这是一个很好的JNA使用范例。

    Java JNA使用参考手册.pdf

    Java JNA使用参考手册.pdf

    JNA 使用方法

    JNA可以让你像调用一般java方法一样直接调用本地方法。就和直接执行本地方法差不多,而且调用本地方法还不用额外的其他处理或者配置什么的,也不需要多余的引用或者编码,使用很方便。 文档写的很全。

    JNA 转java接口以及指针结构体解析

    经过几天的奋战,终于让我搞懂了JNA的解析以及指针在结构体中的应用!!!下了很多的资料,里面包含c++的.h头文件,给需要帮助的人看看!! 里面包含代码以及解析过程。

    jna-platform-4.0.0.jar、4.1.0.jar、4.2.0.jar、4.2.1.jar、4.2.2.jar及JNA使用方法、程序示例

    内部包含6个文件,其中五个是最新JNA jar包,包括jna-platform-4.1.0.jar、jna-platform-4.2.0.jar、jna-platform-4.2.1.jar、jna-platform-4.2.2.jar,一个是JNA介绍文档,包括在线帮助、入门示例、简单程序示例等...

    jna-4.5.1 , jna-4.5.1-sources , jna-platform-4.5.1 jar包

    jna-4.5.1 , jna-4.5.1-sources , jna-platform-4.5.1 jar包 JNA全称Java Native Access,是一个建立在经典的JNI技术之上的Java开源框架(https://github.com/twall/jna)。JNA提供一组Java工具类用于在运行期动态...

    (002)Jna转换器(可运行)

    【注意】这是一款JNA转换器源码(能使用运行) JNA类库使用一个很小的本地类库sub 动态的调用本地代码。程序员只需要使用一个特定的java接口描述一下将要调用的本地代码的方法的结构和一些基本属性。这样就省了为了...

    jna-5.5.0.jar中文文档.zip

    jna-***.jar中文文档.zip,java,jna-***.jar,net.java.dev.jna,jna,***,com.sun.jna,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 ...

    jna-4.1.0-API文档-中文版.zip

    赠送jar包:jna-4.1.0.jar; 赠送原API文档:jna-4.1.0-javadoc.jar; 赠送源代码:jna-4.1.0-sources.jar; 赠送Maven依赖信息文件:jna-4.1.0.pom; 包含翻译后的API文档:jna-4.1.0-javadoc-API文档-中文(简体)版...

    jna-4.3.0-API文档-中文版.zip

    赠送jar包:jna-4.3.0.jar; 赠送原API文档:jna-4.3.0-javadoc.jar; 赠送源代码:jna-4.3.0-sources.jar; 赠送Maven依赖信息文件:jna-4.3.0.pom; 包含翻译后的API文档:jna-4.3.0-javadoc-API文档-中文(简体)版...

    jna-5.4.0.jar中文文档.zip

    jna-***.jar中文文档.zip,java,jna-***.jar,net.java.dev.jna,jna,***,com.sun.jna,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 ...

    jna-5.0.0.jar中文文档.zip

    jna-***.jar中文文档.zip,java,jna-***.jar,net.java.dev.jna,jna,***,com.sun.jna,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 ...

    JNA实例 JNA实例 JNA实例

    JNA实例=======================================================JNA实例

    jna-4.0.0.jar中文文档.zip

    jna-***.jar中文文档.zip,java,jna-***.jar,net.java.dev.jna,jna,***,com.sun.jna,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 ...

    jna-4.4.0.jar中文文档.zip

    jna-***.jar中文文档.zip,java,jna-***.jar,net.java.dev.jna,jna,***,com.sun.jna,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 ...

    使用JNA获取窗口句柄,并发送消息

    使用JNA获取窗口句柄,并发送消息 可以使用applet的方式,实现 CS架构的SSO.

    jna-5.10.0.jar中文文档.zip

    jna-***.jar中文文档.zip,java,jna-***.jar,net.java.dev.jna,jna,***,com.sun.jna,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 ...

    jna 小例子

    使用jna操作(C或C++)编写的dll动态链接库,其中包括了各种函数操作类型和声明类型,包括基本函数、引用、指针类型,结构体、结构的引用、结构体指针。回调函数等等

Global site tag (gtag.js) - Google Analytics