Java调用C动态库


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);
    }
}

文章作者: superzqbo
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 superzqbo !
评论
  目录