Java调⽤C语⾔动态库(JNA⽅式):回调函数、结构体数组
传参、结构体数组返回
⼀、开发环境
系统、开发环境:win7、eclipse 32位、jdk 32位、jre 32位
由于这⾥使⽤的dll⽂件是32位的,⽽我本⾝的环境是64位的,包括eclipse、jdk、jre都是64位,所以这⾥需要开发环境共存(32位、64位共存),如果本来就是32位环境就不⽤重新搭建环境了。从以下连接分别下载32位软件:
Eclipse IDE for Java EE Developers,  247 MB        Windows 32 Bit
2.jdk 32位,安装⽬录:D:\Program Files\java\jdk32
Windows x86 123.49MB     
3.jre 32位,安装⽬录:D:\Program Files\java\jre32
Windows Offline(32-bit)    fileSize:  27.7MB
要让32位和64位eclipse共存,需要修改eclipse⽬录下的⽂件:eclipse.ini
在原环境变量(JAVA_HOME指向64位⽬录)不改变的情况下在上⾯⽂件内增加两⾏:
-vm
D:\Program Files\java\jdk32\
以上的作⽤使32位eclipse指向32位jdk。
4.JNA下载,这⾥是放在百度云⾥⾯的,下载两个⽂件:jna-3.
5.1.jar、platform-3.5.1.jar,放到⽬录:D:\Program
Files\java\JNA_3.5.1
⾄于JNA是什么,它本⾝是基于JNI技术的,然后进⾏封装以⽅便dll调⽤。这⾥不再详述,⽹上很多。
⼆、调⽤⽅法
1.简单函数调⽤
关于jar包导⼊就不提了,创建⼯程:DemoTools,这⾥使⽤的dll是:libSDK.dll,把该⽂件放到⼯程⽬录下。
dll提供的接⼝函数:
int System_Init (int version, char* encoding);
java代码->声明部分:
import com.sun.jna.Library;
import com.sun.jna.Native;
public class getSDK {
public interface Function extends Library {
Function instanceDll  = (Function)Native.loadLibrary("libSDK.dll",Function.class);
public int System_Init(int version, String encoding);
}
}
java代码->调⽤部分:
result = getSDK.Function.instanceDll.System_Init(1, "");
参数类型⽐较简单时,调⽤也⽐较容易。
2.回调函数调⽤
当dll的接⼝函数需要回调函数作为参数时,使⽤以下⽅法实现:
dll接⼝函数及回调函数类型:
typedef void (*Callback_Status)(char *station_id, char *station_ip, int status);
int Start_Server(char *ip, int port, Callback_Status fun);
java代码->回调函数声明:
import com.sun.jna.win32.StdCallLibrary.StdCallCallback;
public class getSDK {
java jnapublic interface Callback_Status extends StdCallCallback {
public void Status(String station_id, String station_ip, int status);
}
}
java代码->回调函数实现:
public class getSDK {
public static class Status_Realize implements Callback_Status{
public void Status(String station_id, String station_ip, int status) {
if (status == 2) {
GUI.Station_online(station_id, station_ip, 1, 0);
} else if (status == 3) {
GUI.Station_online(station_id, station_ip, 2, 0);
}
}
}
java代码->dll接⼝调⽤:
public static getSDK.Callback_Status callback_status = new getSDK.Status_Realize();
result = getSDK.Function.instanceDll.Start_Server("0.0.0.0", 1234, callback_status);
3.回调函数含有结构体数组参数
当回调函数其中⼀个参数是结构体数组时的处理⽅法:
dll接⼝函数、 回调函数类型,结构体类型 :
typedef struct result_data {
char Station_id[3];
char Label_id[7];
int Signal;
int Power;
int Status;
}Tstatus, *PTstatus;
typedef void (*Callback_Data)(char *station_id, char *station_ip, Tstatus ret_data[], int count);
int Start_Server (char *server_ip, int listen_port, Callback_Status callback_status, Callback_Data callback_data);
java代码->回调函数、结构体定义:
import com.sun.jna.Structure;
public class getSDK {
public interface Function extends Library {
public static class Tstatus extends Structure {
public byte[] Station_id = new byte[3];
public byte[] Label_id = new byte[7];
public int Signal;
public int Power;
public int Status;
public static class ByReference extends Tstatus implements
Structure.ByReference {}
public static class ByValue extends Tstatus implements
Structure.ByValue {}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
protected List getFieldOrder() {
List a = new ArrayList();
a.add("Station_id");
a.add("Label_id");
a.add("Signal");
a.add("Power");
a.add("Status");
return a;
}
}
public int Start_Server(String server_ip, int port, getSDK.Callback_Status Callback_Status,getSDK.Callback_Data Callback_Data); }
public interface Callback_Data extends StdCallCallback {
public void Data(String station_id, String station_ip, Pointer data, int count);
}
}
java代码->回调函数实现:
public class getSDK {
public static class Data_Realize implements Callback_Data{
public void Data(String station_id, String station_ip, Pointer data, int count) {
int srow, frow;
srow = 0;
frow = 0;
for (int i = 0; i < count; i++) {
byte[] stationbuf = new byte[2];
byte[] labelbuf = new byte[6];
int[] signal = new int[1];
int[] power = new int[1];
int[] status = new int[1];
String labelID = new String(labelbuf);
String stationID = new String(stationbuf);
}
}
}
}
java代码->接⼝调⽤:
public static getSDK.Callback_Status callback_status = new getSDK.Status_Realize();
public static getSDK.Callback_Data callback_data = new getSDK.Data_Realize();
result = getSDK.Function.instanceDll.Start_Server("0.0.0.0", 1234, callback_status, callback_data);
这⾥的难点就在处理回调函数的结构体数组参数,参数是从dll传出来的,java⾥⾯⽤指针接收,⽽获取结构体内部的每个值就需要⽤读内存的⽅式读取出来,这⾥就需要对结构体在内存中的存储⽅式⽐较了解才⾏,因为read函数需要指定:内存起始位置、接收数据数组变量、数组变量的第⼏个元素、取内存⼤⼩,4个参数。
上⾯源码中i*24作⽤是取到结构体数组的第⼆、第三、、、个元素。也就是这⾥的结构体占内存⼤⼩为24,看下⾯:
在32位系统中char占1个字节,int占4个字节,算下来结构体TStatus应该是22个字节,实际上还有⼀个内存对齐的概念,结构体前两个char数组共10个字节(是连续存储的),⽽结构体分配内存的⼤⼩必须是该结构体中占字节最⼤类型的倍数,所以应该分配4字节的倍数即12字节,所以前两个char数组实际分配了12个字节,在取数据时,第三个int的偏移量是12,整个结构体的⼤⼩为12 + 3*4(三个int 变量)= 24字节
4.接⼝函数参数为结构体数组
当接⼝函数的参数为结构体数组,并且结构体成员也为结构体数组时,调⽤⽅法:
dll接⼝函数 类型,结构体类型 :
typedef unsigned int UINT;
typedef struct code_word {
char Feild[8];
BOOL Inverse;
UINT Length;
CHAR Payload[255];
}Cword, *pCword;
typedef struct label_data {
char Label_id[7];
UINT Count;
Cword NCword[50];
}Ldata, *pLdata;
int Start_Update (char *station_id, int count, Ldata data[]); java代码->结构体定义,接⼝函数声明:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。