目录
第一次写JNA相关的文章是在21年了,中间由于一些事情把后续搁置了,现在补上Java模拟结构体、结构体指针以及结构体中嵌套结构体数组。如果对JNA还不了解,可以先阅读 JNA基础之Java映射char*、int*、float*、double*一文。
1 JNA模拟C结构体
要使用Java类模拟C的结构体,需要Java类继承Structure类。
必须注意,继承Structure类的子类中的公共成员的顺序,必须与C语言结构体中变量的顺序保持一致
,否则会报错!因为,Java 调用动态链接库中的C 函数,实际上就是一段内存作为函数的参数传递给C函数。动态链接库以为这个参数就是C 语言传过来的参数。同时,C 语言的结构体是一个严格的规范,它定义了内存的次序。因此,JNA 中模拟的结构体的变量顺序绝对不能错。
如果一个Struct有2个int变量int a, int b,如果JNA中的顺序和C语言中的顺序相反,那么不会报错,但是数据将会被传递到错误的变量中去。
Structure 类代表了一个原生结构体。当Structure 对象作为一个函数的参数或者返回值传递时,它代表结构体指针。当它被用在另一个结构体内部作为一个字段时,它代表结构体本身。
另外,Structure 类有两个内部接口Structure.ByReference 和Structure.ByValue。这两个接口仅仅是标记,如果一个类实现Structure.ByReference 接口,就表示这个类代表结构体指针。如果一个类实现Structure.ByValue接口,就表示这个类代表结构体本身。如果不实现这两个接口,那么就相当于你实现了Structure.ByReference接口。
使用这两个接口的实现类,可以明确定义我们的Structure 实例表示的是结构体指针还是结构体本身。
1.1 结构体本身作参数
假设有这样一个C语言结构体:
struct User{
long id;
char* name;
int age;
};
使用上述结构体的函数:
extern "C"{
void sayUser(User user);
}
void sayUser(User user){
printf("id:%ld\n",user.id);
printf("name:%s\n",user.name);
printf("age:%d\n",user.age);
}
JNA中可以这样写:
public class Test {
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("/libJNADEMO.so", CLibrary.class);
public static class UserStruct extends Structure{
public NativeLong id;
public String name;
public int age;
public static class ByReference extends UserStruct implements Structure.ByReference{
}
public static class ByValue extends UserStruct implements Structure.ByValue{
}
@Override
protected List getFieldOrder(){
return Arrays.asList(new String[] {
"id", "name", "age"});
}
}
void sayUser(UserStruct.ByValue user);
}
public static void main(String[] args) {
CLibrary.UserStruct.ByValue user = new CLibrary.UserStruct.ByValue();
user.id = new NativeLong(100001);
user.name = "张三";
user.age = 29;
CLibrary.INSTANCE.sayUser(user);
}
}
运行结果如下:
1.2 结构体指针作参数
仍然使用1.1中的结构体,C函数修改为下面的:
extern "C"{
void sayUser(User* user);
}
void sayUser(User *user){
printf("use structure pointer\n");
printf("id:%ld\n",user->id);
printf("name:%s\n",user->name);
printf("age:%d\n",user->age);
}
JNA代码中,修改函数声明为:
void sayUser(UserStruct.ByReference
user);
JNA main函数中修改为:
CLibrary.UserStruct.ByReference user = new CLibrary.UserStruct.ByReference();
user.id = new NativeLong(100390301);;
user.name = "test";
user.age = 29;
CLibrary.INSTANCE.sayUser(user);
运行结果如下:
1.3 结构体内部嵌套结构体(结构体本身作参数)
C语言最复杂的数据类型就是结构体。结构体的内部可以嵌套结构体,这使它可以模拟任何类型的对象。JNA 也可以模拟这类复杂的结构体,结构体内部可以包含结构体对象指针的数组。
假设有如下结构体:
struct User{
long id;
char* name;
int age;
};
struct CompanyStruct{
long id;
const char* name;
User users[3];
int count;
};
如下的C函数:
// 头文件函数声明
extern "C"{
void showNestedStruct(CompanyStruct cst); //结构体本身做参数
}
// 函数定义
void showNestedStruct(CompanyStruct cst){
printf("This is nested struct\n");
printf("company id is:%ld\n",cst.id);
printf("company name:%s\n",cst.name);
for (int i = 0; i < 3; i++){
printf("user[%d] info of company\n",i);
printf("user id:%ld\n",cst.users[i].id);
printf("user name:%s\n",cst.users[i].name);
printf("user age:%d\n",cst.users[i].age);
}
printf("count %d\n",cst.count);
}
JNA代码:
import com.sun.jna.*;
import java.util.Arrays;
import java.util.List;
public class Test {
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("/libJNADEMO.so", CLibrary.class);
public static class UserStruct extends Structure{
public NativeLong id;
public String name;
public int age;
public static class ByReference extends UserStruct implements Structure.ByReference{
}
public static class ByValue extends UserStruct implements Structure.ByValue{
}
@Override
protected List getFieldOrder(){
return Arrays.asList(new String[] {
"id","name","age"});
}
}
public static class CompanyStruct extends Structure{
public NativeLong id;
public String name;
public UserStruct.ByValue[] users = new CLibrary.UserStruct.ByValue[3];
public int count;
public static class ByReference extends CompanyStruct implements Structure.ByReference{
};
public static class ByValue extends CompanyStruct implements Structure.ByValue{
};
@Override
protected List getFieldOrder(){
return Arrays.asList(new String[] {
"id","name","users","count"});
}
}
//函数声明, 对应C函数void showNestedStruct(CompanyStruct cst);
void showNestedStruct(CompanyStruct.ByValue com