ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

一行代码引起的dll类库“爆炸”事件!

2021-06-19 11:55:06  阅读:259  来源: 互联网

标签:类库 int 代码 PointerByReference dll JNA void 指针


今天在使用JNA调用dll动态链接库时“爆炸”了!

直接使用JNI调用dll或者so库时比较繁琐,使用JNI调用dll或者so共享类库是也非常非常麻烦和痛苦的。

如果有一个现有的dll或者so文件,如果使用JNI技术调用,我们首先需要另外使用C语言写一个dll或者so共享库,使用SUN规定的数据结构替代C语言的数据结构,调用已有的dll或者so中公布的函数。

然后再在Java中载入这个适配器dll或者so,再编写Java native函数作为dll中函数的代理。

经过上面两个繁琐的步骤才能在Java中调用本地代码。

不信,你就试试,我是受够了这种调用方式的。那有什么方式能够简化JNI的调用过程吗?答案当然是:有。

在《Java中一个逐渐被遗忘的强大功能,强到你难以置信!!》一文中,我写了如何使用JNA来调用dll库,小伙伴们可以看一下。

然而在使用JNA调用dll的时候却“爆炸”了。

问题再现

当时我兴奋的使用c语言快速写了相应的算法,将其打包成dll库,使用JNA调用dll库时,却报错了,报错信息如下所示。

Exception in thread "Thread-1" java.lang.Error: Invalid memory access

在这里插入图片描述

表面上看是内存访问错误。但是细想的话,应该是类型转换出现了问题。因为我在写dll库的时候,方法中使用了int* 类型的指针。

那问题怎么解决呢?

解决问题

其实,JNA关于指针映射这块是有自己的类型的。int* 对应的是IntByReference这个类型。于是我把Java中对应C语言的int* 类型的参数由 int 修改为IntByReference,再次调用dll库中的方法,成功了。

问题是解决了,下面再为小伙伴们分享下有关JNA与C语言函数对应关系的知识。

JNA扩展

JNA模拟普通传值参数

C语言函数:

int function1(int a, float b, long c)

JNA模拟:

int function1(int a, float b, long c)

JNA模拟C语言数组

C语言函数:

void function1(char * data)
void function2(const unsigned char* data)

JNA模拟:

void function1(char[] data) 或者 void function1(byte[] data) 
void function2(char[] data) 或者 void function2(byte[] data)

JNA模拟基本类型指针

JNA的ByReference有很多子类,这些类都在com.sun.jna.ptr包中:

IntByReference,LongByReference,FloatByReference,DoubleByReference,ShortByReference、ByteByReference、PointerByReference等等

从这些名字大家应该可以看出来他们的作用。

下面直接上例子吧:

C语言函数:

long function(int * a, long * b, float * c, double * d, short * e)

JNA模拟:

long function(IntByReference aRef, LongByReference bRef, FloatByReference cRef, DoubleByReference dRef, ShortByReference eRef)

如何构建这些对象呢?

FloatByReference cRef = new FloatByReference();   //使用默认初始值(具体多少我也不知道)
FloatByReference cRef = new FloatByReference(0);  //初始值为0

调用方法和普通参数一样:

function(..., cRef, ...);

获取结果值:

float fVal = cRef.getValue();

JNA模拟指针、指针的指针、模拟void *,void **等指针

C语言函数:

void function(int * pInt, int ** ppInt, void * pVoid, void ** ppVoid)

JNA模拟:

void function(IntByReference pInt, PointerByReference ppInt, Pointer pVoid, PointerByReference ppVoid)

调用举例:

IntByReference pInt = new IntByReference(0);
PointerByReference ppInt = new PointerByReference(Pointer.NULL); //指向指针的指针,初始化为NULL
Pointer pVoid = Pointer.NULL; //创建一个指向NULL的指针
PointerByReference ppVoid = new PointerByReference(Pointer.NULL);

调用:function(pInt, ppInt, pVoid, ppVoid);

(1)PointerByReference是指向指针的指针,遇到指针的指针都可以使用它来模拟,那么如何获取到它指向的指针呢?

Pointer p = ppVoid.getValue(); //获取指针

(2)如何获取指针的指针呢?

Pointer p1 = ....;
PointerByReference pp1 = new PointerByReference(p1);
PointerByReference ppp1 = new PointerByReference(pp1.getPointer());

JNA看着复杂,其实都很简单!JNA要比JNI好用多了,以后就用JNA了。

后面有时间再扒一扒JNA的源码,分享给小伙伴们。

 

 

标签:类库,int,代码,PointerByReference,dll,JNA,void,指针
来源: https://blog.51cto.com/binghe001/2927149

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有