JNA中級篇 回調函數詳解

        JNI 技術是雙向的,既能夠從Java 代碼中調用原生函數,也能夠從原生函數中直接建立
Java 虛擬機,並調用Java 代碼。可是在原生函數中調用java代碼要寫大量C代碼,這對大多數java程序員來講是很頭疼的。java

       使用JNA,咱們不用編寫C代碼就能在原生代碼中調用java代碼。JNA 能夠模擬函數指針,經過函數指針,就能夠實如今原生代碼中調用Java 函數。程序員

       下面直接用代碼進行說明:ide

       原生代碼定義:函數

//方法定義
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代碼實現:.net

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 代碼。code

      代碼說明:xml

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流寫入具體結構體中,才能解析數據。所以,這裏對結構體的定義要求必須徹底正確,即每一個字段的長度,字段的順序都必須嚴格對應原生代碼中的結構體,不然解析結果就會不正確。blog

歡迎指出本文有誤的地方,轉載請註明原文出處https://my.oschina.net/7001/blog/672662ip

相關文章
相關標籤/搜索