java调用C++动态库
由于项目,需要调用明华IC卡读卡器接口,项目使用的语言是java,所以需要用到java的JNA技术,去调用C的DLL动态库
一、JNI、JNA介绍
java调用C的方式有两种JNA、JNI
JNI(Java Native Interface):通过使用 Java本地接口书写程序,可以确保代码在不同的平台上方便移植
JNA(Java Native Access):提供一组Java工具类用于在运行期间动态访问系统本地库(native library:如Window的dll)而不需要编写任何Native/JNI代码。开发人员只要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射。
简而言之,就是jna基于jni的方式封装了很多api,在使用上面相对于jni来说简化了很多。JNA全称Java Access,是一个建立在经典的JNI技术之上的Java开源框架。JNA提供一组Java工具类用于在运行期动态访问系统本地库(native library:如Window的dll)而不需要编写任何Native/JNI代码。开发人员只要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射。
需要注意的是:在使用JNI技术调用dll动态链接库时,32位dll只能是32位JDK去调用,64位dll只能是64位JDK去调用。这个必须是这样的,如果发现无法调用或者提示版本错误,首先要检查下JDK的位数和dll的位数是否是对应的。
二、代码演示
1、引入jar包
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.12.1</version>
</dependency>
2、定义接口,创建动态库实例和动态库接口
1、接口需要继承Library类
2、定义动态库接口
3、定义动态库实例
package com.test.jnademo.utils;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.ptr.IntByReference;
import java.io.File;
/**
* @ClassName JnaUtils
* @description:
* @author: codesheep
* @Version 1.0.0
* @createTime: 2022-07-18 09:10:47
*/
public class JnaInterface {
/**
* @description: 明华IC卡读卡器接口:IC(Integrated Circuit)卡,也被称作智能卡(Smart Card),具有写入数据和存储数据的功能,IC卡内存储器的内容可以根据需要有条件地供外部读取,完成信息处理和判定。
* IC卡是携带应用信息和数据的媒体,空白IC卡是不能立即使用的,必须对IC卡应用系统进行初始化,写入系统IC卡和个人密码,个人专用信息和应用数据,所以需要用到读卡器进行操作
* @author: bozhiqiang
* @updateTime: 2022/7/18 10:33
*/
public interface MwIc extends Library {
//////////////////////////////////////////////////// 动态库实例 //////////////////////////////////////////////////////
// load需要指定绝对路径
File file = new File("src/main/resources/lib/Mwic_32.dll");
MwIc INSTANCE = Native.load(file.getAbsolutePath(),MwIc.class);
//////////////////////////////////////////////////// 动态库接口 //////////////////////////////////////////////////////
/**
* 说明:初始化通讯接口
* 调用:Port: 通讯口号 0、1、2、3 分别代表串口 1、2、3、4 ; baud: 通讯口为串口时代表波特率,其值可为 1200-115200
* 返回: <0 错误 ; >0 通讯设备标识符
* 举例: icdev=ic_init(0,9600);初始化串口 1,波特率为 9600
*/
public int ic_init(int port,long baud);
/**
* 说明: 关闭通讯口,串口、USB 接口都使用这个函数
* 调用: icdev: 通讯设备标识符
* 返回: <0 错误;=0 正确
* 举例: st=ic_exit(icdev);
*/
public short ic_exit(int icdev);
/**
* 说明: 读写器蜂鸣(RD 读写器专用函数)
* 调用: icdev: 通讯设备标识符;time: 蜂鸣时间,值范围 0-255(单位 10ms)
* 返回: <0 错误;=0 正确
* 举例: st=ic_beep(icdev,100);
*/
public short dv_beep(int icdev,short time);
/**
* 说明: 读取设备版本号
* 调用: icdev: 通讯设备标识符,len: 版本号字符串长度,其值为 18,databuff: 存放读取的版本号字符串
* 返回: <0 错误,=0 正确
* 举例: unsigned char databuff[18];st=srd_ver(icdev,18,databuff);
*/
public short srd_ver(int icdev,short len,byte[] databuff);
/**
* 说明: 检查卡型是否正确
* 调用: icdev: 通讯设备标识符
* 返回: <0 错误,=0 正确
* 举例: st=chk_4442(icdev)
*/
public short chk_4442(int icdev);
/**
* 说明: 返回设备当前状态
* 调用: icdev: 通讯设备标识符
* state: 插卡状态
* 1)有检测脚的卡座,读写器返回 4 种插卡状态:
* 00——无卡
* 01——有用户卡
* 返回: <0 错误;=0 正确,
* 举例: int status;st=get_status(icdev,&status);
*/
public short get_status(int icdev, IntByReference statu);
public short srd_4442(int icdev,short offset,short len,byte[] data_buffer);
public short swr_4442(int icdev,short offset,short len,byte[] data_buffer);
public short prd_4442(int icdev,short len,byte[] data_buffer);
public short pwr_4442(int icdev,short offset,short len,byte[] data_buffer);
public short csc_4442(int icdev,short len,byte[] data_buffer);
public short wsc_4442(int icdev,short len,byte[] data_buffer);
public short rsc_4442(int icdev,short len,byte[] data_buffer);
public short rsct_4442(int icdev,IntByReference counter);
public short hex_asc(byte[] hex,byte[] asc,short len);
public short asc_hex(byte[] asc,byte[] hex,short len);
}
}
3、工具类封装
package com.test.jnademo.utils;
import com.sun.jna.ptr.IntByReference;
/**
* @ClassName JnaUtils
* @description:
* @author: bozhiqiang
* @Version 1.0.0
* @createTime: 2022-07-18 10:38:25
*/
public class JnaUtils {
public static class MwIc{
/**
* @param args
*/
int icdev=0;
short st=1;
byte[] ver=new byte[20];
public void DevConnect(JnaInterface.MwIc epen) {
icdev=epen.ic_init(0, 9600);
st=epen.srd_ver(icdev, (short)18, ver);
if(st!=0) {
System.out.println("ic_init error!");
}
else {
String str=new String(ver,0,18);
System.out.println(str);
}
epen.dv_beep(icdev, (short)30);
}
public void disconnectDev(JnaInterface.MwIc epen) {
epen.ic_exit(icdev);
//System.out.println("ceshi");
}
public void Card4442(JnaInterface.MwIc epen) {
IntByReference ret = new IntByReference();
st=epen.get_status(icdev, ret);
if(st!=0) {
System.out.println("get_status error!");
}
else {
System.out.println("ret is "+ ret.getValue());
}
st=epen.chk_4442(icdev);
if(st!=0) {
System.out.println("chk_4442 error!");
}
IntByReference counter=new IntByReference();
st=epen.rsct_4442(icdev, counter);
if(st!=0) {
System.out.println("rsct_4442 error!");
}
else {
System.out.println(counter.getValue());
}
}
}
}
4、调用
package com.test.jnademo;
import com.test.jnademo.utils.JnaInterface;
import com.test.jnademo.utils.JnaUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class JnaDemoApplicationTests {
@Test
void contextLoads() {
JnaInterface.MwIc epen = JnaInterface.MwIc.INSTANCE;
if (epen != null){
System.out.println("DLL连接成功!");
} else{
System.out.println("DLL连接失败!");
}
JnaUtils.MwIc con=new JnaUtils.MwIc();
con.DevConnect(epen);
con.Card4442(epen);
con.disconnectDev(epen);
}
}