java jna 回调函数_JNA中级篇 回调函数详解

JNI 技术是双向的,既可以从Java 代码中调用原生函数,也可以从原生函数中直接创建

Java 虚拟机,并调用Java 代码。但是在原生函数中调用java代码要写大量C代码,这对大多数java程序员来说是很头疼的。

使用JNA,我们不用编写C代码就能在原生代码中调用java代码。JNA 可以模拟函数指针,通过函数指针,就可以实现在原生代码中调用Java 函数。

下面直接用代码进行说明:

原生代码定义:

//方法定义

LONG StartListenServer(const Alarm_Listen_Param *param);

//Alarm_Listen_Param结构体

struct{

IpAddress struIPAdress;

MessageCallBack fnMsgCb;

void *pUserData;

BYTE byProtocolType;

BYTE byRes[31];

}Alarm_Listen_Param, *Alarm_Listen_Param;

//ip结构体

struct{

char szIP[128];

WORD wPort;

BYTE byRes[2];

}IpAddress, *IpAddress;

//回调函数声明

typedef BOOL (CALLBACK *MessageCallBack)(

LONG iHandle,

AlarmMessage *pAlarmMsg,

void *pUserData

);

//启动参数结构体

struct{

DWORD alarmType;

void *alarmInfo;

DWORD alarmInfoLen;

void *pXmlBuf;

DWORD xmlBufLen;

BYTE byRes[32];

}AlarmMessage, *AlarmMessage;

//返回值结构体

struct{

DWORD dwSize;

char alarmTime[32];

char deviceID[256];

DWORD alarmType;

DWORD alarmAction;

DWORD videoChannel;

DWORD alarmInChannel;

DWORD diskNumber;

BYTE remark[64];

BYTE retransFlag;

BYTE byRes[63];

}AlarmInfo,*AlarmInfo;

java代码实现:

public interface AlarmServer extends StdCallLibrary{

public static final int UNKNOWN =0;

public static final int ALARM =1;

public static final int REPORT =3;

public final static int MAX_DEVICE_ID_LEN =256;

public final static int MAX_TIME_LEN =32;

public final static int MAX_REMARK_LEN =64;

//创建唯一实例

AlarmServer INSTANCE=(AlarmServer ) Native.loadLibrary("AlarmServer",AlarmServer .class);

//启动参数结构体

public static class Alarm_Listen_Param extends Structure{

public IpAddress struIPAdress;

public MessageCallBack fnMsgCb;//回调函数

public Pointer pUserData;

public byte byProtocolType;

public byte[] byRes=new byte[31];

}

//ip结构体

public static class IpAddress extends Structure{

public byte[] ip=new byte[128];

public short port;

public byte[] byRes=new byte[2];

}

//回调函数参数结构体

public static class AlarmMessage extends Structure{

public int alarmType;//类型

public Pointer alarmInfo;//内容

public int alarmInfoLen;//缓冲区大小

public String xmlBuf;//内容(XML)

public int xmlBufLen;//内容大小

public byte[] byRes=new byte[20];

}

//返回值结构体

public static class AlarmInfo extends Structure{

public int size;

public byte[] alarmTime=new byte[MAX_TIME_LEN];

public byte[] deviceID=new byte[MAX_DEVICE_ID_LEN];

public int alarmType;

public int alarmAction;

public int videoChannel;

public int alarmInChannel;

public int diskNumber;

public byte[] remark=new byte[MAX_REMARK_LEN];

public byte retransFlag;

public byte[] byRes=new byte[63];

}

//回调函数定义

public static interface MessageCallBack extends StdCallCallback{

public boolean invoke(NativeLong iHandle,

AlarmMessage pAlarmMsg,Pointer pUserData);

}

}

回调函数实现类:

//回调函数具体实现类,处理业务逻辑

public class AlarmServerImpl {

public static class MessageCallBackImpl implements MessageCallBack{

public boolean invoke(NativeLong iHandle,

AlarmMessage alarmMsg,Pointer pUserData){

boolean isSuccess=false;

try{

int dwType=alarmMsg.alarmType;

switch(dwType){

case AlarmServer.UNKNOWN:

System.out.println("未知类型");

break;

case AlarmServer.ALARM:

AlarmInfo alarmInfo=new AlarmInfo();

alarmInfo.write();

Pointer p=alarmInfo.getPointer();

p.write(0,alarmMsg.alarmInfo.getByteArray(0,

alarmMsg.alarmInfoLen),0, alarmMsg.alarmInfoLen);

alarmInfo.read();

System.out.println("设备id="+newString(alarmInfo.deviceID).trim());

System.out.println("报警内容="+alarmMsg.xmlBuf);

//...具体业务逻辑

case AlarmServer.REPORT:

//...具体业务逻辑

break;

default:

break;

}

isSuccess=true;

}catch(Exception e){

e.printStackTrace();

}

return isSuccess;

}

}

}

原生函数可以通过函数指针实现函数回调,调用外部函数来执行任务。JNA 可以方便地模拟函数指针,把Java 函数作为函数指针传递给原生函数,实现在原生代码中调用Java 代码。

代码说明:

AlarmInfo alarmInfo=new AlarmInfo();

alarmInfo.write();

Pointer p=alarmInfo.getPointer();

p.write(0,alarmMsg.alarmInfo.getByteArray(0,alarmMsg.alarmInfoLen),0, alarmMsg.alarmInfoLen);

alarmInfo.read();

alarmMsg.alarmInfo在结构体中是指针类型,指向的内容根据dwType不同而不同,由于Pointer指向的是内存块,因此需要将内存中的数据转为byte流写入具体结构体中,才能解析数据。因此,这里对结构体的定义要求必须完全正确,即每个字段的长度,字段的顺序都必须严格对应原生代码中的结构体,否则解析结果就会不正确。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值