一行代码引起的dll类库“爆炸”事件!
作者:互联网
今天在使用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