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中级篇 回调函数详解相关推荐

  1. 『中级篇』Dockerfile详解(17)

    一般的,Dockerfile 分为四部分:基础镜像信息.维护者信息.镜像操作指令和容器启动时执行指令. ####官网学习 https://docs.docker.com/engine/referenc ...

  2. Java工程师学习指南(中级篇)

    Java工程师学习指南 中级篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我写的文章都是站 ...

  3. 【备战春招/秋招系列】美团Java面经总结终结篇 (附详解答案)

    该文已加入开源项目:JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识的文档类项目,Star 数接近 14 k).地址:https://github.com/Snailclimb.. ...

  4. 【备战春招/秋招系列】美团Java面经总结终结篇 (附详解答案) 1

    该文已加入开源项目:JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识的文档类项目,Star 数接近 14 k).地址:https://github.com/Snailclimb/J ...

  5. java调用javascript函数_[Java教程]JavaScript函数的4种调用方法详解

    [Java教程]JavaScript函数的4种调用方法详解 0 2016-08-09 00:00:12 在JavaScript中,函数是一等公民,函数在JavaScript中是一个数据类型,而非像C# ...

  6. 【备战春招/秋招系列】美团Java面经总结进阶篇 (附详解答案)

    <!-- MarkdownTOC --> 一 消息队列MQ的套路 1.1 介绍一下消息队列MQ的应用场景/使用消息队列的好处 ①.通过异步处理提高系统性能 ②.降低系统耦合性 1.2 那么 ...

  7. MySQL数据库,从入门到精通:第十二篇——MySQL数据类型详解

    MySQL数据库,从入门到精通:第十二篇--MySQL数据类型详解 第 12 章_MySQL数据类型精讲 1. MySQL中的数据类型 2. 整数类型 2. 1 类型介绍 2. 2 可选属性 2. 2 ...

  8. 【python教程入门学习】Python函数定义及传参方式详解(4种)

    这篇文章主要介绍了Python函数定义及传参方式详解(4种),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 一.函数初识 1.定 ...

  9. spring之旅第四篇-注解配置详解

    spring之旅第四篇-注解配置详解 一.引言 最近因为找工作,导致很长时间没有更新,找工作的时候你会明白浪费的时间后面都是要还的,现在的每一点努力,将来也会给你回报的,但行好事,莫问前程!努力总不会 ...

最新文章

  1. 安全自动化在于信任,而非技术
  2. ChromeDriver启动Chrome浏览器后,地址栏只显示data;——chromeDriver版本不对
  3. 毕业课题之------------图像的形态学滤波
  4. QT中Sqlite的使用
  5. 线程池 ManualResetEvent
  6. boost::sort模块使用 string_sort 使用复杂的多部分键对结构进行排序
  7. msysGit管理GitHub代码
  8. Java架构师在线视频,架构师的7大必备技能
  9. 藉上帝之旨,行时代之命的文学长征
  10. 【资源下载】《Pytorch模型训练实现教程》(附下载链接)
  11. 动态网页和静态网页的区别是什么?
  12. 【深度学习】图像匹配Siamese网络实验记录
  13. 基于买方意向的货物撮合交易_CCF货物撮合交易赛题 Baseline
  14. python分类器鸢尾花怎么写_机器学习之路: python k近邻分类器 鸢尾花分类预测
  15. C++中的const完全解析
  16. 电脑蓝牙耳机,蓝牙耳机能连笔记本吗_笔记本电脑怎么接蓝牙耳机吗-win7之家
  17. Linux操作系统面试题
  18. epson连接计算机后无法打印,电脑连接爱普生打印机后无法打印如何解决
  19. ptaa乘以b_PTA-多项式A除以B
  20. 微信公众号的前端热门文章及链接(不定期更新)

热门文章

  1. MySQL数据库创建索引
  2. 前端javascript百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换
  3. 描述Koa2洋葱模型
  4. 网页设计与开发-实验报告-3
  5. 关于ojdbc14的bug
  6. matlab Runtime R2017b在centos7中部署运行的问题
  7. Intellij idea使用Statistic统计代码行数的方法
  8. R语言时间序列分析小例
  9. 基于节能减排理念的校园电气设计研究
  10. Axure中如何引入自定义javascript