文档章节

JNA中级篇 回调函数详解

AbeJeffrey
 AbeJeffrey
发布于 2016/05/10 11:16
字数 892
阅读 3.6K
收藏 1

        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流写入具体结构体中,才能解析数据。因此,这里对结构体的定义要求必须完全正确,即每个字段的长度,字段的顺序都必须严格对应原生代码中的结构体,否则解析结果就会不正确。

欢迎指出本文有误的地方,转载请注明原文出处https://my.oschina.net/7001/blog/672662

© 著作权归作者所有

AbeJeffrey
粉丝 51
博文 43
码字总数 116095
作品 0
杭州
高级程序员
私信 提问
加载中

评论(0)

JNA 基础篇 结构体

1.JNA模拟结构体 原生函数定义: java使用下面的方式模拟结构体: JNA中,定义一个类型继承Structure 类,用这个类来模拟C 语言的结构体。必须注意,Structure 子类中的公共字段的顺序,必须...

AbeJeffrey
2016/05/09
1.4K
0
JNA工作笔记二

定义一个回调函数: //JNA CALLBACK方法定义,断线回调,如果你是标准的继承StdCallback,否则Callbackpublic interface fDisConnect extends StdCallCallback { public int invoke(NativeLong......

吕兵阳
2015/12/18
343
3
微信小程序教学第三章第四节(含视频):小程序中级实战教程:下拉更新、分享、阅读标识

下拉更新、分享、阅读标识 本文配套视频地址: v.qq.com/x/page/h055… 开始前请把 分支中的 目录导入微信开发工具 这一篇中,我们把列表这块的剩余功能做完:下拉更新、分享、阅读标识。 下...

iKcamp
2017/10/30
0
0
运维学python之爬虫高级篇(六)scrapy模拟登陆GitHub和51cto

上一篇介绍了如何爬取豆瓣TOP250的相关内容,今天我们来模拟登陆GitHub。 1 环境配置 2 爬取前分析 分析登陆提交信息 分析登陆信息我使用的是fiddler,fiddler的使用方法就不作介绍了,大家可...

578384
2018/02/14
0
0
如何在ArcGIS Online中构建自己的应用程序模板初级篇-显示地图

开发ArcGIS Online应用程序模板之前,需要了解怎么使用ArcGIS API for JavaScript。 在ArcGIS Online当中如何构架自己的应用程序模板,我们得先要了解ArcGIS Online如何解析这个web地图的。 ...

长平狐
2012/11/28
946
0

没有更多内容

加载失败,请刷新页面

加载更多

网站变灰

平时到哀悼日的时候,我们看到很多知名网站都变成灰色了 只需要加下面的样式即可 html { filter: url(“data:image/svg+xml;utf8,<svg xmlns=\’http://www.w3.org/2000/svg\’><filter id=\...

三蹦子
32分钟前
67
0
网站首页蒙灰CSS样式

每次全国哀悼日,各大网站首页都变成了灰色,添加以下全局CSS样式,可以实现此效果: html,html *{  filter:gray!important;  filter:progid:DXImageTransform.Microsoft.BasicImage(...

达时索
38分钟前
74
0
1.NET Core 概述

.NET Core 概述 .NET Core是一个免费的、开源的、跨平台的、广泛使用的Web框架;它是由微软维护的。社区广泛参与支持的一个框架。.NET Core可以运行在:Windows、MacOS以及Linux操作系统上。...

osc_8j0twt2u
46分钟前
41
0
2.ASP.NET Core概述

ASP.NETCore概述 ASP.NET Core是最新的ASP.NET Web开发框架,它主要定向于运行在.NET Core平台上。 ASP.NET Core是免费的、开源的、跨平台的框架,可以用于编写基于云的应用程序,例如:Web...

osc_oa6qrgun
47分钟前
69
0
计算与软件工程作业三

作业要求 https://edu.cnblogs.com/campus/jssf/infor_computation17-31/homework/10454 我在这个课程的目标是 掌握软件开发知识,自己设计简单的程序,发布并维护 此作业在哪个具体方面帮我...

osc_kl6fknqf
47分钟前
88
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部