背景
Java通过调用C的动态库,得到数据。
结构体样式
开始测试样式
public class A extend Structure {
public byte[] name = new byte[256];
public Pointer value = new Memory(1024 * 64);
public IntByference size = new IntByference ();
public A(){
super();
}
public static class ByValue extends A implements Structure.ByValue{}
public static class ByReference extends A implements Structure.ByReference {}
@Override
proteced List<String> getFieldOrder(){return Arrays.asList("name","pValue","length");}
}
最终样式
public class A extend Structure {
public byte[] name;
public Pointer value;
public IntByference size;
public A(){
super();
}
public static class ByValue extends A implements Structure.ByValue{}
public static class ByReference extends A implements Structure.ByReference {}
@Override
proteced List<String> getFieldOrder(){return Arrays.asList("name","pValue","length");}
}
问题
1、首先是调用接口一直报错,invalid memory access
。
2、然后接口可以调通,值却拿不到。
3、接口调通,但是嵌入式库写数据时,报错invalid memory access
。
4、接口调通,可以写入数据,但只能写进去结构体数组0号位置的信息,从1号位开始就报错invalid memory access
。
5、获取到嵌入式的值,但是数组里面的值打印出现错误。
解决
问题一,调用接口一直报错,invalid memory access
原因是数据类型不匹配,通过Java和C的类型关系映射就解决了。
报错invalid memory access – Java调用JNA
问题二,接口可以调通,值却拿不到
通过分析嵌入式代码,发现嵌入式自己开辟了新的空间,将地址值传了出来,这样我们是获取不到值得,必须由Java这边开辟内存,然后嵌入式写进去才能获取到值。
问题三,嵌入式库写数据时,报错invalid memory access
通过让嵌入式那边打印,调试发现,结构体的指针为空,内存没有,写的时候报错。
我查看了我的写法
public class JnaService{
public interface CLibrary extends Library{
int test(Pointer a);
}
}
A[] as = new A[1024];
for(int i = 0; i< a.length;i++){
as[i] = new A();
}
Clibrary instance= Native.load(path,CLibrary.class);
instance.test(as[0].getPointer);
问题原因
创建的结构体数组,通过new初始化,内存空间不是连续的,这种情况,用int test(A[] as);
,这种方式接的话,就会看到报错,structure array elements must use contiguoud memory
。所以出错原因就是没创建连续空间,故这种方式不能用。
解决方法
public class JnaService{
public interface CLibrary extends Library{
int test(A[] as);
}
}
A[] as = (A[])new A().toArray(1024);
Clibrary instance= Native.load(path,CLibrary.class);
instance.test(as);
这样就解决内存问题,但会引出问题4
问题四,接口调通,可以写入数据,但只能写进去结构体数组0号位置的信息,从1号位开始就报错invalid memory access
经过问题三的修复,发现,虽然有地址值,但是还是无法写入,然后通过嵌入式的打印,定位到了,只能写0索引位置的内容,其他仍然是空。这就说明,只有第一个值初始化空间了,马上整体初始化
A[] as = (A[])new A().toArray(1024);
for(A a : as){
a.name = new byte[256];
a.value = new Memory(1024 * 64);
a.size = new IntByference (0);
}
Clibrary instance= Native.load(path,CLibrary.class);
instance.test(as);
然后结构体可以改为
public class A extend Structure {
public byte[] name;
public Pointer value;
public IntByference size;
public A(){
super();
}
public static class ByValue extends A implements Structure.ByValue{}
public static class ByReference extends A implements Structure.ByReference {}
@Override
proteced List<String> getFieldOrder(){return Arrays.asList("name","pValue","length");}
}
这样就解决传值空间没开辟的问题
问题5,获取到嵌入式的值,但是数组里面的值打印出现错误。
当获取数组中的值时候,需要用特殊的方式,因为得到的是指针,所以需要根据偏移取值,一个double是8,所以,填8*i
就行,不然会报错或者获取错误数据
private List<Double> getValue(Pointer p,int len){
List<Double> result = new ArrayList<>();
for(int i = 0;i<len;i++){
try{
result.add(pValue.getDouble(i*8))//一个Double的长度8
}catch(Exception e){
log.error(i+" 超出范围 ”+len);//需要在类上加注解@Slf4j
break;
}
}
return result;
}
这样就能把数据解析出来了。
至此全部解决。