JNA框架调用dll动态库(给你整得明明白白)

本文详细介绍了如何使用Java的JNA框架调用DLL动态库,包括环境准备、API调用步骤以及解决各种错误的方法。在环境准备中,需确保JDK版本与DLL位数匹配,并正确导入JNA库。API调用分为可释放和不可释放两种方式。遇到的问题包括动态库加载失败、编码问题、参数类型定义错误以及Invalid memory access错误,文中给出了相应的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java调用dll动态库的方法,总的有三种:JNI、JNA、JNative。其中JNA调用DLL是最方便的。网上文章一大堆,我就不废话了。

使用JNA框架调用DLL动态库,步骤如下:

一、环境准备

1.导jar包

jar:jar包版本可以选择,不过好像没什么太大影响,5.8.0的也阔以
pom:

 <!--动态库调用-->
        <dependency>
            <groupId>com.sun.jna</groupId>
            <artifactId>jna</artifactId>
            <version>3.0.9</version>
        </dependency>

2.准备好你的dll文件

dll文件有32位和64位的,首先搞清楚你的目标dll是多少位的,然后你的JDK版本位数必须和dll文件保持一致,我本地是搞了好几个JDK7、8、9、32位的互相切换。配JDK可以参考下面https://blog.youkuaiyun.com/xiongyouqiang/article/details/79352596?spm=1001.2014.3001.5506
还是不明白怎么切换的可以评论或者私信我!

二、API调用

重头戏来了,和数据库连接一样,JNA连接动态库也是一次资源连接。
如果整个过程你只需要调用一次动态库函数,那就可以选择调完释放的api,如果不确定调用次数,就不释放。

1、调完可释放

/*
* 动态库初始化
*/
//DLL_PATH:DLL文件地址
NativeLibrary INSTANCE = NativeLibrary.getInstance(DLL_PATH);
//动态库的一个函数
String NationEcTrans(String strUrl, String InData, Pointer OutData);
//调用函数
String returnCode = ElecCertDll.INSTANCE.getFunction("NationEcTrans").invokeString(new Object[]{strUrl, input, outPut}, false);
//释放动态库连接,也可以不释放,没有太大关系
ElecCertDll.INSTANCE.dispose();
        

2、调完不释放

 /**
  * @Description: 初始化动态库
  * SSCardInterfaceProcess.SSCardDll.class是接口类
  */
SSCardInterfaceProcess.SSCardDll INSTANCE = (SSCardInterfaceProcess.SSCardDll) Native.loadLibrary(DLL_PATH, SSCardInterfaceProcess.SSCardDll.class);

//动态库的一个函数
NativeLong Init(String pUrl, String pUser);
//调用函数
NativeLong initCode = SSCardDll.INSTANCE.Init(pUrl, pUser);

三、各种错误解决

1、java.lang.UnsatisfiedLinkError: Unable to load library 'C:\Windows\System32\NISEC_SKSC.dll

无法加载动态库,有两个原因如下:
a、路径错误,无论是绝对路径还是相对路径,路径没错都是可行的。网上说了很多一定要使用相对路径或者绝对路径,这个我不认同。需要注意的是,debug出来的路径明明是正确的,也有可能报这个错误。可以参考我这个写法,

 /**
     * 项目根路径
     */
    public static String ROOT_PATH;
    /**
     * 动态库名称
     */
    public static final String DLL_NAME = "NationECCode.dll";

    /**
     * 动态库名称
     */
    public static String DLL_PATH;

    static {
        try {
        	//window是\\,linux是/
            String separator = System.getProperty("os.name").contains("Windows") ? "\\" : "/";
            //这里我是看到网上有人这么搞,我也是这么搞,才没有问题。原因也不得其解!
            ROOT_PATH = (ElecCertInterfaceProcess.class.getResource("/").getPath()).replaceAll("%20", " ").substring(1).replace("/", separator);
            String url = "dll"+separator+"elecCert"+separator+"32"+separator;
            DLL_PATH = URLDecoder.decode(ROOT_PATH,"utf-8") +url+DLL_NAME;
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());
        }
    }

b、动态库支持的jdk版本和你环境的jdk版本不一致
这个没办法,要么你jdk换掉,要么叫提供动态库的人给你另外搞个版本。

2、乱码问题

无非就是dll和本地环境编码不一致的。
jna默认的编码方式是utf-8,所以需要对应的做修改。
如果dll编码格式是GBK的
在代码的开头设置编码格式就好了

   System.setProperty("jna.encoding", "GBK");

3、动态库接口函数,方法参数定义有误

我的动态库是C++写的,有个函数回参是long类型的,我用java的long去接受,直接就报错了。后来看了C和java类型的对照,原来C的long需要java用NativeLong来接收。下面是C、C++和java的对照关系

C++Java
char *String
wordshort
bytebyte
byte[]byte[]
dwordint
longNativeLong
Void *Pointer
lpvoidPointer
lpDwordIntByReference
HWNDHWND
char[]byte[]
byte *Pointer
JAVAC
Java类型 C类型原生表现
booleanint 32位整数(可定制)
bytechar 8位整数
charwchar_t 平台依赖
shortshort 16位整数
intint 32位整数
longlong,__int64 64位整数
floatfloat 32位浮点数
doubledouble 64位浮点数
Buffer/Pointerpointer 平台依赖(32或64位指针)
pointer/array32或64位指针(参数/返回值)邻接内存(结构体成员)
String char*/0结束的数组(nativeencodingorjna.encoding)
WStringwchar_t* /0结束的数组(unicode)
String[]char** /0结束的数组的数组
WString[]wchar_t** /0结束的宽字符数组的数组
Structurestruct*/struct 指向结构体的指针(参数或返回值)(或者明确指定是结构体指针)结构体(结构体的成员)(或者明确指定是结构体)
Unionunion 等同于结构体
Structure[]struct[] 结构体的数组,邻接内存
Callback(*fp)() Java函数指针或原生函数指针
NativeMappedvaries 依赖于定义
NativeLonglong 平台依赖(32或64位整数)
PointerTypepointer 和Pointer相同

另外char*也可以用内存来接收
com.sun.jna.Memory
com.sun.jna.Poniter

Pointer outPut = new Memory(1024 * 10);
String outPutJsonStr = outPut.getString(0);

4、Invalid memory access在这里插入图片描述

这个错误基本可以理解为内存溢出,但是并不是java这边内存溢出了,而是dll那边因为某种原因返回了这样的一个错误。很多同学说是,动态库函数的参数类型定义错误或者长度定义错误,会报这个错误,但是我另一个函数就函数名不一样,其他都一样。由于自己才疏学浅,不懂C\C++。所以错误的根本原因一直没有找到。困扰了我近一周的时间,因为之前的调动态库的容器是JRE,后面改成JDK之后就没这个问题了。估计是某些dll函数依赖了JDK的一些编译环境吧???!!!

新的解决办法,给读卡器换个USB接口就好了,离谱!!!

评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值