系列文章:
Java通过JNI调用C++动态链接库dll,并打在jar包内 ——JNA-JNI(一)
Java使用JNA调用C++动态链接库——JNA-JNI(二)
Mac M1 Xcode创建动态链接库dylib(c++)——JNA-JNI(三)
JNA调用dll(c++)附带解析xml——JNA-JNI(四)
JNA参数类型转换(含接收、发送结构体)——JNA-JNI(五)
JNA参数类型转换(含接收、发送结构体)——JNA-JNI(五)
官网映射关系查看c++结构体JNA调用
编写结构体声明函数调用运行结果 可能报错
官网映射关系查看https://java-native-access.github.io/jna/5.5.0/javadoc/
实现两个例子,java部分
- 一个分别发送和接收,都使用结构体另一个只发送结构体,无返回值
#ifndef SIMPLE_H_INCLUDED #define SIMPLE_H_INCLUDED #includeusing namespace std; typedef struct Student { int Gender; char *Mobile; int Email; void *column; }; typedef struct Location { int longitude; int latitude; char *info; void *column; }; #ifdef __cplusplus #define EXPORT extern "C" __declspec (dllexport) #else #define EXPORT __declspec (dllexport) #endif // __cplusplus EXPORT void xmltest(Student s); EXPORT Location struc(Location l); #endif // SIMPLE_H_INCLUDED
#includeJNA调用 编写结构体#include #include #include #include "xxx.h" using namespace std; void xmltest(Student s) { cout << s.Gender << endl; cout << s.Mobile << endl; cout << s.Email << endl; cout << s.column << endl; } Location struc(Location l) { cout << l.longitude << endl; cout << l.latitude << endl; cout << l.info << endl; cout << l.column << endl; struct Location s1;//定义结构体类型变量s1 s1.longitude = 1;//结构体变量的引用 s1.latitude = 2; const char *s = "nowloc"; s1.info = (char*)s; s1.column = &s; return s1; }
在Java端复写结构体,在复写的时候需要注意两点:
- 需要在结构体定义中定义2个内部类ByReference和ByValue,来实现指针类型接口和值类型接口重写getFieldOrder()来告诉C/C++的成员取值次序,结构体定义取值次序,需要与c++中对齐,不然报NoSuchFieldError错误!
收发
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.List;
public class Location extends Structure {
public static class ByReference extends Location implements Structure.ByReference{ }
public static class ByValue extends Location implements Structure.ByValue{ }
public int longitude;
public int latitude;
public String info;
public Pointer column;
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"longitude", "latitude", "info", "column"});
}
}
只发不收
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.List;
public class QueryStructure extends Structure {
public int Gender;
public String Mobile;
public int Email;
public Pointer column;
public static class ByReference extends QueryStructure implements Structure.ByReference{}
public static class ByValue extends QueryStructure implements Structure.ByValue{}
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[] {"Gender", "Mobile", "Email", "column"});
}
}
关于ByReference和ByValue
- 只要涉及到结构体的传递,必须使用ByReference或者ByValue中的一种指针和引用的传递使用ByReference拷贝参数传递使用ByValue
区别主要在声明处,如果收发的话,使用ByValue,只发不接收使用ByReference,否则会报错Exception in thread "main" java.lang.Error: Invalid memory access
public interface CLibrary extends Library {
DemoApplication.CLibrary INSTANCE = (DemoApplication.CLibrary) Native.loadLibrary("Project6", DemoApplication.CLibrary.class); // 引入库文件
public void xmltest(QueryStructure.ByReference queryInfo);
public Location.ByValue struc(Location.ByValue l);
}
调用
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class);
//
QueryStructure.ByReference qs = new QueryStructure.ByReference();
qs.Gender = 1;
qs.Mobile = "222";
qs.Email = 3;
qs.column = Pointer.createConstant(2431128);
DemoApplication.CLibrary.INSTANCE.xmltest(qs);
//
Location.ByValue ins = new Location.ByValue();
ins.latitude = 3;
ins.longitude = 4;
ins.info = "oldloc";
ins.column = Pointer.createConstant(2431128);
Location.ByValue res = CLibrary.INSTANCE.struc(ins);
System.out.println(res.latitude);
System.out.println(res.longitude);
System.out.println(res.info);
System.out.println(res.column);
}
}
运行结果
只发不收的结果
收发结果
Exception in thread “main” java.lang.Error: Invalid memory access
原因:数据类型不对应



