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流写入具体结构体中,才能解析数据。因此,这里对结构体的定义要求必须完全正确,即每个字段的长度,字段的顺序都必须严格对应原生代码中的结构体,否则解析结果就会不正确。
java jna 回调函数_JNA中级篇 回调函数详解相关推荐
- 『中级篇』Dockerfile详解(17)
一般的,Dockerfile 分为四部分:基础镜像信息.维护者信息.镜像操作指令和容器启动时执行指令. ####官网学习 https://docs.docker.com/engine/referenc ...
- Java工程师学习指南(中级篇)
Java工程师学习指南 中级篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我写的文章都是站 ...
- 【备战春招/秋招系列】美团Java面经总结终结篇 (附详解答案)
该文已加入开源项目:JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识的文档类项目,Star 数接近 14 k).地址:https://github.com/Snailclimb.. ...
- 【备战春招/秋招系列】美团Java面经总结终结篇 (附详解答案) 1
该文已加入开源项目:JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识的文档类项目,Star 数接近 14 k).地址:https://github.com/Snailclimb/J ...
- java调用javascript函数_[Java教程]JavaScript函数的4种调用方法详解
[Java教程]JavaScript函数的4种调用方法详解 0 2016-08-09 00:00:12 在JavaScript中,函数是一等公民,函数在JavaScript中是一个数据类型,而非像C# ...
- 【备战春招/秋招系列】美团Java面经总结进阶篇 (附详解答案)
<!-- MarkdownTOC --> 一 消息队列MQ的套路 1.1 介绍一下消息队列MQ的应用场景/使用消息队列的好处 ①.通过异步处理提高系统性能 ②.降低系统耦合性 1.2 那么 ...
- MySQL数据库,从入门到精通:第十二篇——MySQL数据类型详解
MySQL数据库,从入门到精通:第十二篇--MySQL数据类型详解 第 12 章_MySQL数据类型精讲 1. MySQL中的数据类型 2. 整数类型 2. 1 类型介绍 2. 2 可选属性 2. 2 ...
- 【python教程入门学习】Python函数定义及传参方式详解(4种)
这篇文章主要介绍了Python函数定义及传参方式详解(4种),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 一.函数初识 1.定 ...
- spring之旅第四篇-注解配置详解
spring之旅第四篇-注解配置详解 一.引言 最近因为找工作,导致很长时间没有更新,找工作的时候你会明白浪费的时间后面都是要还的,现在的每一点努力,将来也会给你回报的,但行好事,莫问前程!努力总不会 ...
最新文章
- 安全自动化在于信任,而非技术
- ChromeDriver启动Chrome浏览器后,地址栏只显示data;——chromeDriver版本不对
- 毕业课题之------------图像的形态学滤波
- QT中Sqlite的使用
- 线程池 ManualResetEvent
- boost::sort模块使用 string_sort 使用复杂的多部分键对结构进行排序
- msysGit管理GitHub代码
- Java架构师在线视频,架构师的7大必备技能
- 藉上帝之旨,行时代之命的文学长征
- 【资源下载】《Pytorch模型训练实现教程》(附下载链接)
- 动态网页和静态网页的区别是什么?
- 【深度学习】图像匹配Siamese网络实验记录
- 基于买方意向的货物撮合交易_CCF货物撮合交易赛题 Baseline
- python分类器鸢尾花怎么写_机器学习之路: python k近邻分类器 鸢尾花分类预测
- C++中的const完全解析
- 电脑蓝牙耳机,蓝牙耳机能连笔记本吗_笔记本电脑怎么接蓝牙耳机吗-win7之家
- Linux操作系统面试题
- epson连接计算机后无法打印,电脑连接爱普生打印机后无法打印如何解决
- ptaa乘以b_PTA-多项式A除以B
- 微信公众号的前端热门文章及链接(不定期更新)