发布时间:2025-06-24 20:34:24 作者:北方职教升学中心 阅读量:978
创建Pointer:
//这样的指针变量定义很像C的写法,就是在定义的时候申请空间。
发布时间:2025-06-24 20:34:24 作者:北方职教升学中心 阅读量:978
创建Pointer:
//这样的指针变量定义很像C的写法,就是在定义的时候申请空间。
为AIX平台提供公共库映射。
struct_nested_param.c
#include<stdio.h>structUser{longid;char*name;intage;};structCompany{longid;constchar*name;structUserusers[3];intcount;};voidshowNestedStruct(structCompanycompany){printf("This is nested struct.\n");printf("company id is:%ld\n",company.id);printf("company name is:%s\n",company.name);for(inti =0;i <3;i++){printf("user[%d] info of companyn",i);printf("user id:%ldn",company.users[i].id);printf("user name:%sn",company.users[i].name);printf("user age:%dn",company.users[i].age);}printf("count %d\n",company.count);}
编译为共享库struct_nested_param.dylib:
gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin -dynamiclib-ostruct_nested_param.dylib struct_nested_param.c
JNA调用:
publicclassStructNestedParamTest{//描述本地共享库publicinterfaceLibStructNestedParamextendsLibrary{LibStructNestedParamINSTANCE=Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_nested_param.dylib",LibStructNestedParam.class);//定义User结构体classUserStructextendsStructure{//公共字段的顺序,必须与C语言中的结构的顺序保持一致publicNativeLongid;publicStringname;publicintage;// 定义值传递和指针传递类publicstaticclassByReferenceextendsUserStructimplementsStructure.ByReference{//指针和引用的传递使用ByReference}publicstaticclassByValueextendsUserStructimplementsStructure.ByValue{//拷贝参数传递使用ByValue}// 重写getFieldOrder获取字段列表, 很重要,没有会报错@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"id","name","age"});}}//定义Company结构体classCompanyStructextendsStructure{//公共字段的顺序,必须与C语言中的结构的顺序保持一致publicNativeLongid;publicStringname;publicUserStruct.ByValue[]users =newUserStruct.ByValue[3];publicintcount;// 定义值传递和指针传递类publicstaticclassByReferenceextendsCompanyStructimplementsStructure.ByReference{//指针和引用的传递使用ByReference}publicstaticclassByValueextendsCompanyStructimplementsStructure.ByValue{//拷贝参数传递使用ByValue}// 重写getFieldOrder获取字段列表, 很重要,没有会报错@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"id","name","users","count"});}}//描述本地函数,值传递voidshowNestedStruct(CompanyStruct.ByValuecompany);}publicstaticvoidmain(String[]args){LibStructNestedParam.UserStruct.ByValueuser1 =newLibStructNestedParam.UserStruct.ByValue();user1.id =newNativeLong(1);user1.name ="zhangsan";user1.age =18;LibStructNestedParam.UserStruct.ByValueuser2 =newLibStructNestedParam.UserStruct.ByValue();user2.id =newNativeLong(2);user2.name ="lisi";user2.age =19;LibStructNestedParam.UserStruct.ByValueuser3 =newLibStructNestedParam.UserStruct.ByValue();user3.id =newNativeLong(3);user3.name ="wangwu";user3.age =20;LibStructNestedParam.CompanyStruct.ByValuecompany =newLibStructNestedParam.CompanyStruct.ByValue();company.id =newNativeLong(1000001);company.name ="XXXXXX有限责任公司";company.count =3;company.users[0]=user1;company.users[1]=user2;company.users[2]=user3;LibStructNestedParam.INSTANCE.showNestedStruct(company);}}
输出:
Thisis nested struct.company id is:1000001company name is:XXXXXX有限责任公司user[0]info of companyuser id:1user name:zhangsanuser age:18user[1]info of companyuser id:2user name:lisiuser age:19user[2]info of companyuser id:3user name:wangwuuser age:20count 3
//设置intint_pointer.setInt(0,123);//设置doubledouble_pointer.setDouble(0,22.33);
Pointer的getXxx方法提供了为各种类型获取值的方法:
获取单个值的参数为偏移量,获取数组还需要传递一个获取数量。
为OS X平台提供公共库映射。Structure类
JNA 全称 Java Native Access,是一个建立在经典的 JNI 技术之上的 Java 开源框架。案例
提供Com Utilities.
提供com实用程序注释
为Windows CE平台提供公共库映射。
struct_nested_array_param.c
#include<stdio.h>typedefstruct{intenable;intx;inty;intwidth;intheight;}area_pos;typedefstruct{intenable;intx;inty;}spot_pos;typedefstruct{intenable;intsta_x;intsta_y;intend_x;intend_y;}line_pos;typedefstruct{area_pos area[2];spot_pos spot[2];line_pos line;}image_pos;voidget_struct_array_value(image_pos *img_data){printf("line_pos enable:%d\n",img_data->line.enable);printf("line_pos sta_x:%d\n",img_data->line.sta_x);printf("line_pos sta_y:%d\n",img_data->line.sta_y);printf("line_pos end_x:%d\n",img_data->line.end_x);printf("line_pos end_y:%d\n",img_data->line.end_y);for(inti =0;i<2;i++){printf("area_pos[%d] enable:%dn",i,img_data->area[i].enable);printf("area_pos[%d] x:%dn",i,img_data->area[i].x);printf("area_pos[%d] y:%dn",i,img_data->area[i].y);printf("area_pos[%d] width:%dn",i,img_data->area[i].width);printf("area_pos[%d] height:%dn",i,img_data->area[i].height);}for(intj =0;j <2;j++){printf("spot_pos[%d] enable:%dn",j,img_data->spot[j].enable);printf("spot_pos[%d] x:%dn",j,img_data->spot[j].x);printf("spot_pos[%d] y:%dn",j,img_data->spot[j].y);}}
编译为共享库struct_nested_array_param.dylib:
gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin -dynamiclib-ostruct_nested_array_param.dylib struct_nested_array_param.c
JNA调用:
publicclassStructNestedArrayParamTest{publicinterfaceLibStructNestedArrayParamextendsLibrary{LibStructNestedArrayParamINSTANCE=Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_nested_array_param.dylib",LibStructNestedArrayParam.class);classAreaPosextendsStructure{publicintenable;publicintx;publicinty;publicintwidth;publicintheight;publicstaticclassByReferenceextendsAreaPosimplementsStructure.ByReference{}publicstaticclassByValueextendsAreaPosimplementsStructure.ByValue{}@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"enable","x","y","width","height"});}}classSpotPosextendsStructure{publicintenable;publicintx;publicinty;publicstaticclassByReferenceextendsSpotPosimplementsStructure.ByReference{}publicstaticclassByValueextendsSpotPosimplementsStructure.ByValue{}@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"enable","x","y"});}}classLinePosextendsStructure{publicintenable;publicintsta_x;publicintsta_y;publicintend_x;publicintend_y;publicstaticclassByReferenceextendsLinePosimplementsStructure.ByReference{}publicstaticclassByValueextendsLinePosimplementsStructure.ByValue{}@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"enable","sta_x","sta_y","end_x","end_y"});}}classImagePosextendsStructure{publicAreaPos.ByValue[]area =newAreaPos.ByValue[2];publicSpotPos.ByValue[]spot =newSpotPos.ByValue[2];publicLinePos.ByValueline;publicstaticclassByReferenceextendsImagePosimplementsStructure.ByReference{}publicstaticclassByValueextendsImagePosimplementsStructure.ByValue{}@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"area","spot","line"});}}voidget_struct_array_value(ImagePos.ByReferenceimg);}publicstaticvoidmain(String[]args){LibStructNestedArrayParam.AreaPos.ByValuea1 =newLibStructNestedArrayParam.AreaPos.ByValue();a1.enable =1;a1.x =10;a1.y =20;a1.height =1080;a1.width =1920;LibStructNestedArrayParam.AreaPos.ByValuea2 =newLibStructNestedArrayParam.AreaPos.ByValue();a1.enable =0;a1.x =20;a1.y =10;a1.height =1920;a1.width =1080;LibStructNestedArrayParam.SpotPos.ByValues1 =newLibStructNestedArrayParam.SpotPos.ByValue();s1.enable =0;s1.x =1;s1.y =1;LibStructNestedArrayParam.SpotPos.ByValues2 =newLibStructNestedArrayParam.SpotPos.ByValue();s1.enable =1;s1.x =2;s1.y =2;LibStructNestedArrayParam.LinePos.ByValueline =newLibStructNestedArrayParam.LinePos.ByValue();line.enable =0;line.end_x =10;line.end_y =20;line.sta_x =30;line.sta_y =40;LibStructNestedArrayParam.ImagePos.ByReferenceimg =newLibStructNestedArrayParam.ImagePos.ByReference();img.area[0]=a1;img.area[1]=a2;img.spot[0]=s1;img.spot[1]=s2;img.line =line;LibStructNestedArrayParam.INSTANCE.get_struct_array_value(img);}}
输出:
line_pos enable:0line_pos sta_x:30line_pos sta_y:40line_pos end_x:10line_pos end_y:20area_pos[0]enable:0area_pos[0]x:20area_pos[0]y:10area_pos[0]width:1080area_pos[0]height:1920area_pos[1]enable:0area_pos[1]x:0area_pos[1]y:0area_pos[1]width:0area_pos[1]height:0spot_pos[0]enable:1spot_pos[0]x:2spot_pos[0]y:2spot_pos[1]enable:0spot_pos[1]x:0spot_pos[1]y:0
如果一个 Struct 有 2 个 int 变量 int a, int b,如果 JNA 中的次序和 C 语言中的次序相反,那么不会报错,但是数据将会被传递到错误的字段中去。
这两个接口仅仅是标记:
文件array_param.c
#include<stdio.h>#include<string.h>typedefstruct{intenable;charstatic_ip[20];charnetmask[20];chargateway[20];chardns1[20];chardns2[20];}network_eth;intsdk_set_network_eth(constchar*ip,network_eth *network_param){if(strlen(ip)==0||network_param ==NULL){printf("sdk_set_network_eth param error!n");return-1;}printf("ip:%s\n",ip);printf("network_eth enable:%d\n",network_param->enable);printf("network_eth static_ip:%s\n",network_param->static_ip);printf("network_eth netmask:%s\n",network_param->netmask);printf("network_eth gateway:%s\n",network_param->gateway);printf("network_eth dns1:%s\n",network_param->dns1);printf("network_eth dns2:%s\n",network_param->dns2);return0;}
编译为共享库array_param.dylib:
gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin -dynamiclib-oarray_param.dylib array_param.c
JNA调用:
publicclassCharArrayTest{publicinterfaceLibCharArrayextendsLibrary{LibCharArrayINSTANCE=Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/array_param.dylib",LibCharArray.class);classNetWorkEthextendsStructure{publicintenable;publicbyte[]static_ip =newbyte[20];publicbyte[]netmask =newbyte[20];publicbyte[]gateway =newbyte[20];publicbyte[]dns1 =newbyte[20];publicbyte[]dns2 =newbyte[20];publicstaticclassByReferenceextendsNetWorkEthimplementsStructure.ByReference{}publicstaticclassByValueextendsNetWorkEthimplementsStructure.ByValue{}@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"enable","static_ip","netmask","gateway","dns1","dns2"});}}intsdk_set_network_eth(byte[]ip,NetWorkEth.ByReferencenetWork);}publicstaticvoidmain(String[]args){Stringip ="127.0.0.1";LibCharArray.NetWorkEth.ByReferencenetWorkEth =newLibCharArray.NetWorkEth.ByReference();netWorkEth.enable =1;netWorkEth.static_ip ="10.20.6.10".getBytes();netWorkEth.netmask ="255.255.255.0".getBytes();netWorkEth.gateway ="192.168.122.134".getBytes();netWorkEth.dns1 ="114.114.114.114".getBytes();netWorkEth.dns2 ="8.8.8.8".getBytes();intres =LibCharArray.INSTANCE.sdk_set_network_eth(ip.getBytes(),netWorkEth);System.out.println(res);}
输出:
0ip:127.0.0.1network_eth enable:1network_eth static_ip:10.20.6.10255.255.255.0192.168.122.134114.114.114.1148.8.8.8127.0.0.1network_eth netmask:5.0192.168.122.134114.114.114.1148.8.8.8127.0.0.1network_eth gateway:4.114.114.1148.8.8.8127.0.0.1network_eth dns1:127.0.0.1network_eth dns2:��#mRealVarArgsCheckerlang/O
输出乱码!因为C/C++的数组类型在内存中是连续存储的,而Java的数组不一定是连续的。
目标C程序,struct.c:
#include<stdio.h>#include<stdlib.h>#include<string.h>// teacher 结构体定义typedefstruct{inttea_age;char*tea_name;}Teacher;// student 结构体定义typedefstruct{intstu_age;char*stu_name;}Student;Teacher stuTea(Student stu,Teacher *tea){printf("stu-name=%s/n",stu.stu_name);printf("stu-age=%d/n",stu.stu_age);// 将stu复制给tea做函数返回Teacher teacher;teacher.tea_name =stu.stu_name;teacher.tea_age =stu.stu_age;tea->tea_name =strcat(tea->tea_name,"是好老师");returnteacher;}
函数内部的功能也简单:
编译为共享库struct.dylib:
gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin -dynamiclib-ostruct.dylib struct.c
JNA调用:
publicclassStructTest{//定义一个接口,描述本地库publicinterfaceLibStructextendsLibrary{LibStructINSTANCE=Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct.dylib",LibStruct.class);//定义结构体classTeacherStructextendsStructure{//结构体参数类型及顺序要严格按照C结构体的类型及顺序publicinttea_age;publicStringtea_name;// 定义值传递和指针传递类publicstaticclassByReferenceextendsTeacherStructimplementsStructure.ByReference{//指针和引用的传递使用ByReference}publicstaticclassByValueextendsTeacherStructimplementsStructure.ByValue{//拷贝参数传递使用ByValue}//重写getFieldOrder获取字段列表, 很重要,没有会报错@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"tea_age","tea_name"});}@OverridepublicStringtoString(){return"TeacherStruct{"+"tea_age="+tea_age +", tea_name='"+tea_name +'''+"} "+super.toString();}}//定义结构体classStudentStructextendsStructure{publicintstu_age;publicStringstu_name;// 定义值传递和指针传递类publicstaticclassByReferenceextendsStudentStructimplementsStructure.ByReference{//指针和引用的传递使用ByReference}publicstaticclassByValueextendsStudentStructimplementsStructure.ByValue{//拷贝参数传递使用ByValue}//重写getFieldOrder获取字段列表, 很重要,没有会报错@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"stu_age","stu_name"});}@OverridepublicStringtoString(){return"StudentStruct{"+"stu_age="+stu_age +", stu_name='"+stu_name +'''+"} "+super.toString();}}//描述本地函数TeacherStruct.ByValuestuTea(StudentStruct.ByValuestu,TeacherStruct.ByReferencetea);}publicstaticvoidmain(String[]args){LibStruct.StudentStruct.ByValuestuByValue =newLibStruct.StudentStruct.ByValue();LibStruct.TeacherStruct.ByReferenceteaByReference =newLibStruct.TeacherStruct.ByReference();stuByValue.stu_age =18;stuByValue.stu_name ="小学生";teaByReference.tea_age =48;teaByReference.tea_name ="高级教师";// 调用函数之前System.out.println("调用函数之前teaByReference:"+teaByReference.toString());// 调用方法。C函数文件test.c:
inttest_pointer(inta,int*b){if(a <0){//未对*b进行处理return-1;}*b =a;return0;}
编译为共享库test.dylib:
gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin -dynamiclib-otest.dylib test.c
使用JNA调用该共享库中的test_pointer函数:
publicclassPointerTest{publicinterfaceLibPointerTestextendsLibrary{LibPointerTestINSTANCE=Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/test.dylib",LibPointerTest.class);inttest_pointer(inta,Pointerb);}publicstaticvoidmain(String[]args){inta =-10;Pointerb =newMemory(Native.getNativeSize(Integer.class));intadd =LibPointerTest.INSTANCE.test_pointer(a,b);System.out.println(add);System.out.println(a);System.out.println(b.getInt(0));}}
输出:
-1-100
本文使用的为5.10版,并未发现垃圾值的问题。指针参数Pointer
在JAVA中都是值传递,但是因为使用JNA框架,目标函数是C/C++是有地址变量的,很多时候都需要将变量的结果带回,因此,地址传递在JNA项目中几乎是必须的。
当 C 函数的参数为 char*、动态库版本必须和系统类型匹配
结构体作为参数有两个点,一个是传入,一个是返回。甚至会因为我们对c和msg赋值导致C函数访问到奇怪的地址,导致报错。作为输出参数
结构体中嵌套结构体数组用作输出参数时,需要对结构体数组的第一个元素赋初值。Java模拟C结构体
输出:
调用函数之前teaByReference:TeacherStruct{tea_age=48,tea_name='高级教师'}StructTest$LibStruct$TeacherStruct$ByReference(auto-allocated@0x7ffc36203c40(16bytes)){inttea_age@0x0=0x0030Stringtea_name@0x8=高级教师}调用函数之后teaByReference:TeacherStruct{tea_age=48,tea_name='高级教师是好老师'}StructTest$LibStruct$TeacherStruct$ByReference(auto-allocated@0x7ffc36203c40(16bytes)){inttea_age@0x0=0x0030Stringtea_name@0x8=高级教师是好老师}调用函数返回结果result.name:TeacherStruct{tea_age=18,tea_name='小学生'}StructTest$LibStruct$TeacherStruct$ByValue(auto-allocated@0x7ffc3620b480(16bytes)){inttea_age@0x0=0x0012Stringtea_name@0x8=小学生}stu-name=小学生/nstu-age=18/n
Unable to load DLL 'xxx.dll'
: 找不到指定的模块或者java.lang.UnsatisfiedLinkError: %1
不是有效的 Win32 应用程序。开发人员只要在一个 java 接口中描述目标 native library 的函数与结构,JNA 将自动实现 Java 接口到native function 的映射。64 位的 jdk 只能调用 64 位的 dll,32 位也一样。 各字段顺序对应结构体中的字段即可。错误的调用一
使用这两个接口的实现类,可以明确定义我们的 Structure 实例表示的是结构体指针还是结构体本身。ByReference类
publicclassStructArrayParamTest{publicinterfaceLibStructArrayParamextendsLibrary{LibStructArrayParamINSTANCE=Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_array_param.dylib",LibStructArrayParam.class);classPersonextendsStructure{publicintage;publicbyte[]name =newbyte[20];@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"age","name"});}}//描述函数intchangeObjs(Person[]per,intsize);}publicstaticvoidmain(String[]args){LibStructArrayParam.Personper =newLibStructArrayParam.Person();LibStructArrayParam.Person[]pers =(LibStructArrayParam.Person[])per.toArray(2);pers[0].age =1;pers[0].name =Arrays.copyOf("tom".getBytes(),20);pers[1].age =2;pers[1].name =Arrays.copyOf("jerry".getBytes(),20);LibStructArrayParam.INSTANCE.changeObjs(pers,2);}}
输出:
person[0]age:10person[0]name:wokettasperson[1]age:20person[1]name:wokettas
创建ByReference:
//无参构造,默认值为0IntByReferenceintRef =newIntByReference();//有参构造,根据指定值创建IntByReferenceintRef =newIntByReference(4);
设置/获取值:
//设置intRef.setValue(10);//获取intRef.getValue();
为基于UNIX和X11的平台提供公共图书馆映射。嵌套结构体指针作为参数
struct_nested_pointer_param.c
#include<stdio.h>structUser{longid;char*name;intage;};structCompany{longid;constchar*name;structUserusers[3];intcount;};voidshowNestedStruct(structCompany*company){printf("This is nested struct.\n");printf("company id is:%ld\n",company->id);printf("company name is:%s\n",company->name);for(inti =0;i <3;i++){printf("user[%d] info of companyn",i);printf("user id:%ldn",company->users[i].id);printf("user name:%sn",company->users[i].name);printf("user age:%dn",company->users[i].age);}printf("count %d\n",company->count);}
编译为共享库struct_nested_pointer_param.dylib:
gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin -dynamiclib-ostruct_nested_pointer_param.dylib struct_nested_pointer_param.c
JNA调用:
publicclassStructNestedPointerParamTest{//描述本地共享库publicinterfaceLibStructNestedPointerParamextendsLibrary{LibStructNestedPointerParamINSTANCE=Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_nested_pointer_param.dylib",LibStructNestedPointerParam.class);//定义User结构体classUserStructextendsStructure{//公共字段的顺序,必须与C语言中的结构的顺序保持一致publicNativeLongid;publicStringname;publicintage;// 定义值传递和指针传递类publicstaticclassByReferenceextendsUserStructimplementsStructure.ByReference{//指针和引用的传递使用ByReference}publicstaticclassByValueextendsUserStructimplementsStructure.ByValue{//拷贝参数传递使用ByValue}// 重写getFieldOrder获取字段列表, 很重要,没有会报错@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"id","name","age"});}}//定义Company结构体classCompanyStructextendsStructure{//公共字段的顺序,必须与C语言中的结构的顺序保持一致publicNativeLongid;publicStringname;publicUserStruct.ByValue[]users =newUserStruct.ByValue[3];publicintcount;// 定义值传递和指针传递类publicstaticclassByReferenceextendsCompanyStructimplementsStructure.ByReference{//指针和引用的传递使用ByReference}publicstaticclassByValueextendsCompanyStructimplementsStructure.ByValue{//拷贝参数传递使用ByValue}// 重写getFieldOrder获取字段列表, 很重要,没有会报错@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"id","name","users","count"});}}//描述本地函数,指针传递voidshowNestedStruct(CompanyStruct.ByReferencecompany);}publicstaticvoidmain(String[]args){LibStructNestedPointerParam.UserStruct.ByValueuser1 =newLibStructNestedPointerParam.UserStruct.ByValue();user1.id =newNativeLong(1);user1.name ="zhangsan";user1.age =18;LibStructNestedPointerParam.UserStruct.ByValueuser2 =newLibStructNestedPointerParam.UserStruct.ByValue();user2.id =newNativeLong(2);user2.name ="lisi";user2.age =19;LibStructNestedPointerParam.UserStruct.ByValueuser3 =newLibStructNestedPointerParam.UserStruct.ByValue();user3.id =newNativeLong(3);user3.name ="wangwu";user3.age =20;LibStructNestedPointerParam.CompanyStruct.ByReferencecompany =newLibStructNestedPointerParam.CompanyStruct.ByReference();company.id =newNativeLong(1000001);company.name ="XXXXXX有限责任公司";company.count =3;company.users[0]=user1;company.users[1]=user2;company.users[2]=user3;LibStructNestedPointerParam.INSTANCE.showNestedStruct(company);}}
输出:
Thisis nested struct.company id is:1000001company name is:XXXXXX有限责任公司user[0]info of companyuser id:1user name:zhangsanuser age:18user[1]info of companyuser id:2user name:lisiuser age:19user[2]info of companyuser id:3user name:wangwuuser age:20count 3
在低版本的JNA中,如果C中函数执行失败时,没有对指针进行处理,那么使用Pointer就会得到一个垃圾值。
publicclassHelloWorld{/** * 定义一个接口,默认的是继承Library,如果动态链接库里额函数是以stdcall方式输出的,那么就继承StdCallLibrary * 这个接口对应一个动态连接文件(windows:.dll, linux:.so, mac:.dylib) */publicinterfaceCLibraryextendsLibrary{/** * 接口内部需要一个公共静态常量INSTANCE,通过这个常量就可以获得这个接口的实例,从而使用接口的方法,也就是调用外部dll/so/dylib的函数 * 该常量通过Native.load()这个API获得 * 第一个参数为共享库的名称(不带后缀) * 第二个参数为本接口的Class类型,JNA通过这个这个Class类型,反射创建接口的实例 * 共享库的查找顺序是: * 先从当前类的当前文件夹找,如果没找到 * 再从工程当前文件夹下面找,如果找不到 * 最后在当前平台下面去搜索 */CLibraryINSTANCE=Native.load("c",CLibrary.class);/** * 接口中只需要定义要用到的函数或者公共变量,不需要的可以不定义 * z注意参数和返回值的类型,应该和共享库中的函数诶行保持一致 */voidprintf(Stringformat,Object...args);}publicstaticvoidmain(String[]args){CLibrary.INSTANCE.printf("Hello,World\n");for(inti =0;i <args.length;i++){CLibrary.INSTANCE.printf("Argument %d:%sn",i,args[i]);}}}
运行时指定参数为a b c d
,运行结果如下:
Hello,WorldArgument0:aArgument1:bArgument2:cArgument3:d
struct_nested_array_out.c
#include<stdio.h>typedefstruct{intenable;intx;inty;intwidth;intheight;}area_pos;typedefstruct{intenable;intx;inty;}spot_pos;typedefstruct{intenable;intsta_x;intsta_y;intend_x;intend_y;}line_pos;typedefstruct{area_pos area[2];spot_pos spot[2];line_pos line;}image_pos;voidset_struct_array_value(image_pos *img_data){area_pos a1,a2;a1.enable =1;a1.x =10;a1.y =20;a1.height =1090;a1.width =1920;a2.enable =0;a2.x =20;a2.y =10;a2.height =1920;a2.width =1080;spot_pos s1,s2;s1.enable =0;s1.x =1;s1.y =1;s2.enable =1;s2.x =2;s2.y =2;line_pos l;l.enable =0;l.end_x =10;l.end_y =20;l.sta_x =30;l.sta_y =40;img_data->area[0]=a1;img_data->area[1]=a2;img_data->spot[0]=s1;img_data->spot[1]=s2;img_data->line =l;}
编译为共享库struct_nested_array_out.dylib:
gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin -dynamiclib-ostruct_nested_array_out.dylib struct_nested_array_out.c
JNA调用:
publicclassStructNestedArrayOutTest{publicinterfaceLibStructNestedArrayOutextendsLibrary{LibStructNestedArrayOutINSTANCE=Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_nested_array_out.dylib",LibStructNestedArrayOut.class);classAreaPosextendsStructure{publicintenable;publicintx;publicinty;publicintwidth;publicintheight;publicstaticclassByReferenceextendsAreaPosimplementsStructure.ByReference{}publicstaticclassByValueextendsAreaPosimplementsStructure.ByValue{}@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"enable","x","y","width","height"});}@OverridepublicStringtoString(){return"AreaPos{"+"enable="+enable +", x="+x +", y="+y +", width="+width +", height="+height +"} "+super.toString();}}classSpotPosextendsStructure{publicintenable;publicintx;publicinty;publicstaticclassByReferenceextendsSpotPosimplementsStructure.ByReference{}publicstaticclassByValueextendsSpotPosimplementsStructure.ByValue{}@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"enable","x","y"});}@OverridepublicStringtoString(){return"SpotPos{"+"enable="+enable +", x="+x +", y="+y +"} "+super.toString();}}classLinePosextendsStructure{publicintenable;publicintsta_x;publicintsta_y;publicintend_x;publicintend_y;publicstaticclassByReferenceextendsLinePosimplementsStructure.ByReference{}publicstaticclassByValueextendsLinePosimplementsStructure.ByValue{}@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"enable","sta_x","sta_y","end_x","end_y"});}@OverridepublicStringtoString(){return"LinePos{"+"enable="+enable +", sta_x="+sta_x +", sta_y="+sta_y +", end_x="+end_x +", end_y="+end_y +"} "+super.toString();}}classImagePosextendsStructure{publicAreaPos.ByValue[]area =newAreaPos.ByValue[2];publicSpotPos.ByValue[]spot =newSpotPos.ByValue[2];publicLinePos.ByValueline;publicstaticclassByReferenceextendsImagePosimplementsStructure.ByReference{}publicstaticclassByValueextendsImagePosimplementsStructure.ByValue{}@OverrideprotectedList<String>getFieldOrder(){returnArrays.asList(newString[]{"area","spot","line"});}}voidset_struct_array_value(ImagePos.ByReferenceimg);}publicstaticvoidmain(String[]args){LibStructNestedArrayOut.ImagePos.ByReferenceimg =newLibStructNestedArrayOut.ImagePos.ByReference();// img.area[0] = new LibStructNestedArrayOut.AreaPos.ByValue();// img.spot[0] = new LibStructNestedArrayOut.SpotPos.ByValue();LibStructNestedArrayOut.INSTANCE.set_struct_array_value(img);for(inti =0;i <2;i++)System.out.println(img.area[i]);for(inti =0;i <2;i++)System.out.println(img.spot[i]);System.out.println(img.line);}}
如果未对数组第一项赋值,会报java.lang.IndexOutOfBoundsException
Exceptionin thread "main"java.lang.IndexOutOfBoundsException:Boundsexceeds available space :size=20,offset=40
所以一定要对输出参数中的数组第一项赋值:
publicstaticvoidmain(String[]args){LibStructNestedArrayOut.ImagePos.ByReferenceimg =newLibStructNestedArrayOut.ImagePos.ByReference();img.area[0]=newLibStructNestedArrayOut.AreaPos.ByValue();img.spot[0]=newLibStructNestedArrayOut.SpotPos.ByValue();LibStructNestedArrayOut.INSTANCE.set_struct_array_value(img);for(inti =0;i <2;i++)System.out.println(img.area[i]);for(inti =0;i <2;i++)System.out.println(img.spot[i]);System.out.println(img.line);}
输出:
AreaPos{enable=1,x=10,y=20,width=1920,height=1090}StructNestedArrayOutTest$LibStructNestedArrayOut$AreaPos$ByValue(allocated@0x7fb3b0d1bd10(20bytes)(shared from auto-allocated@0x7fb3b0d1bd10(84bytes))){intenable@0x0=0x0001intx@0x4=0x000Ainty@0x8=0x0014intwidth@0xC=0x0780intheight@0x10=0x0442}AreaPos{enable=0,x=20,y=10,width=1080,height=1920}StructNestedArrayOutTest$LibStructNestedArrayOut$AreaPos$ByValue(allocated@0x7fb3b0d1bd24(20bytes)(shared from auto-allocated@0x7fb3b0d1bd10(84bytes))){intenable@0x0=0x0000intx@0x4=0x0014inty@0x8=0x000Aintwidth@0xC=0x0438intheight@0x10=0x0780}SpotPos{enable=0,x=1,y=1}StructNestedArrayOutTest$LibStructNestedArrayOut$SpotPos$ByValue(allocated@0x7fb3b0d1bd38(12bytes)(shared from auto-allocated@0x7fb3b0d1bd10(84bytes))){intenable@0x0=0x0000intx@0x4=0x0001inty@0x8=0x0001}SpotPos{enable=1,x=2,y=2}StructNestedArrayOutTest$LibStructNestedArrayOut$SpotPos$ByValue(allocated@0x7fb3b0d1bd44(12bytes)(shared from auto-allocated@0x7fb3b0d1bd10(84bytes))){intenable@0x0=0x0001intx@0x4=0x0002inty@0x8=0x0002}LinePos{enable=0,sta_x=30,sta_y=40,end_x=10,end_y=20}StructNestedArrayOutTest$LibStructNestedArrayOut$LinePos$ByValue(allocated@0x7fb3b0d1bd50(20bytes)(shared from auto-allocated@0x7fb3b0d1bd10(84bytes))){intenable@0x0=0x0000intsta_x@0x4=0x001Eintsta_y@0x8=0x0028intend_x@0xC=0x000Aintend_y@0x10=0x0014}
JNA 使用 String 无法直接接收 C 函数返回类型为 char*的值,必须要用 Pointer 进行接收。Pointer类
JNA框架提供了com.sun.jna.Pointer
,指针数据类型,用于匹配转换映射函数的指针变量。
官方网站:https://github.com/java-native-access/jna
Maven依赖:
<dependency><groupId>net.java.dev.jna</groupId><artifactId>jna</artifactId><version>5.10.0</version></dependency>
Package | Description |
---|---|
com.sun.jna | Provides simplified native library access. 提供简化的本机库访问权限。入门案例
|
com.sun.jna.win32 | Provides type and function mappers required for standard APIs on the Windows platform. 提供Windows平台上标准API所需的类型和功能映射器。概述 自定义求和C函数,文件add.c:
编译为共享库add.dylib:
使用JNA调用该共享库中的add函数:
结果显而易见,无论add函数对c和msg做了何种改变,返回java中,值都不会变更。示例一(调用系统共享库) 获取mac平台下的C共享库,然后调用printf函数打印。引用对象ByReference
|
Package | Description |
---|---|
com.sun.jna.platform | Provides cross-platform utilities based on platform-specific libraries. 根据特定于平台的库提供跨平台实用程序。 |
com.sun.jna.platform.win32.COM.tlb.imp | Provides common library mappings for COM Type Library implementations. 为COM类型库实现提供公共库映射。Structure类 要使用 Java 类模拟 C 的结构体,需要 Java 类继承Structure类。 |
com.sun.jna.platform.win32 | Provides common library mappings for the Windows platform. 为Windows平台提供公共库映射。 5.5、结构体数组作为参数
|
com.sun.jna.ptr | Provides various native pointer-to-type ( <type> * ) representations. 提供各种母语指针到类型(<类型> *)表示。引用对象ByReference JNA框架提供了
总的来讲ByReference更加方便,但是对于多层的指针引用,可能Pointer更合适处理嵌套结构。Pointer类 5.3、JNA 提供一组 Java 工具类用于在运行期动态访问系统本地库(native library:如 Window 的 dll)而不需要编写任何 Native/JNI 代码。示例二(调用自定义共享库)自定义一个求和C函数hello.c:
编译为共享库hello.dylib:
使用JNA调用该共享库中的add函数:
输出:
2、结构体本身作为参数 |
com.sun.jna.platform.win32.COM | Provides common library mappings for Windows Component Object Model (COM). 为Windows组件对象模型(COM)提供公共库映射。 必须要注意,Structure子类中的
输出:
|
com.sun.jna.platform.win32.COM.tlb | Provides common library mappings for COM Type Libraries. 指针参数Pointer为COM类型库提供公共库映射。结构体本身作为参数 struct_self_param.c
编译为共享库struct_self_param.dylib:
JNA调用:
输出:
4.3、const char*用做输入时,JNA 可以使用 String 类型进行传 参,此时可以正常调用 C 函数;但当C函数的参数类型为char*且用作输出时,使用 String 类型无法正常接收,必须使用 Pointer 进行处理。Java模拟C结构体 |
Package | Description |
---|---|
com.sun.jna.platform.linux | Provides common library mappings for Linux. 为Linux提供公共图书馆映射。 Java 中模拟结构体时,类名可以和 C 的结构体名称不同,只需要 Java 类的各个字段名称、对C中的char数组类型赋值时,不能直接给数组赋值,要使用 文件char_out.c
编译为共享库char_out.dylib:
JNA调用,使用Pointer接收char*返回值:
输出:
通过 Java 获取 char * 字符串,必须要通过 Java 传入一个 com.sun.jna.Pointer 指针变量,然后在 DLL 中将值赋给此指针变量,然后通过此指针变量获取值。结构体中嵌套结构体数组 1)、入门案例 |
Package | Description |
---|---|
com.sun.jna.internal | Provides internal utilities. 提供内部实用程序。 目录
|
com.sun.jna.platform.unix.solaris | Provides common library mappings for the Solaris (SunOS) platform. 为Solaris(Sunos)平台提供公共图书馆映射。 |
com.sun.jna.platform.dnd | Provides integrated, extended drag and drop functionality, allowing ghosted drag images to be used on all platforms.
提供集成的扩展拖放和丢弃功能,允许缩重拖动图像在所有平台上使用。案例
输出:
3.4、同时,C 语言的结构体是一个严格的规范,它定义了内存的次序。C 语言最复杂的数据类型就是结构体。JNA 也可以模拟这类复杂的结构体,结构体内部可以包含结构体对象指针的数组。常见问题
下一篇:俞祁浩:与冻土“斗智斗勇”
|