首页 > 技术文章 > jna设置回调函数接收c++数组

longsanshi 2020-11-13 20:38 原文

1.启动类及其 如何调用c++的dll文件


import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.win32.StdCall;
import lombok.extern.log4j.Log4j2;

@Log4j2
public class Test {
    CLibrary cLibrary;
    public interface CLibrary extends  Library, StdCall {
        CLibrary INSTANCE = (CLibrary)
            Native.loadLibrary("D:\\subway\\MicsDataSdk\\MicsDataSdk.dll", CLibrary.class);
        void CMicsDataSDK();
        //获取版本号
        String Common_GetVersion();
        //初始化
        int Common_Init(String configPath, String logPath);
        int Common_Start();
        int Common_Stop();
        int Common_SetCallback(CLibrary xx, Callback back);
    }


    public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(()->{
            String configPath="D:\\project\\MicsDataSdk\\config.ini";
            String logPath="";
            CLibrary.INSTANCE.CMicsDataSDK();
            CLibrary.INSTANCE.Common_Init(configPath,logPath);
            IMyDllCallback callback = new MyDllCallbackImpl();
            String s = CLibrary.INSTANCE.Common_GetVersion();
            System.out.println(s);
            CLibrary.INSTANCE.Common_SetCallback(null,callback);
            CLibrary.INSTANCE.Common_Start();
            log.info("sdk启动");
            synchronized (callback) {
                try {
                    System.out.println("进入阻塞,等待数据中...");
                    callback.wait();
                    System.out.println("阻塞完成");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.run();

    }
}

2.要设置回调函数,接口必须继承

import com.sun.jna.Callback;
而且接口里面只能有一个方法,回调接口
import com.sun.jna.Callback;
import com.sun.jna.Pointer;
import com.sun.jna.win32.StdCallLibrary;

import java.io.UnsupportedEncodingException;

/**
 * @author XWF
 *
 */
public interface IMyDllCallback extends StdCallLibrary.StdCallCallback {

    int OnCallback2(Callback Context, int LinkStatus, Pointer  Points, int Size) throws UnsupportedEncodingException;



}

3.实现类,c++的指针数组,在jna里面用

com.sun.jna.Pointer;接收,不能用数组接收
import com.sun.jna.Callback;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import lombok.extern.log4j.Log4j2;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author XWF
 *
 */
@Log4j2
public class MyDllCallbackImpl implements IMyDllCallback {

    @Override
    public int OnCallback2(Callback element, int LinkStatus, Pointer data, int size) throws UnsupportedEncodingException {
        log.info("收到数据长度:"+size);

        List<Element> elementList = pointer2Structure(data, Element.class,size);
        List<ElementVo> voList = new ArrayList<>();
        for (Element element1 : elementList) {
            ElementVo vo = new ElementVo();
            int subSystem = element1.getSubSystem();
            String addr = new String(element1.getAddr(),"GB2312");
            String value = new String(element1.getValue(),"GB2312");

            vo.setSubSystem(subSystem);
            vo.setAddr(addr);
            vo.setValue(value);
            voList.add(vo);
        }
        log.info("数据为:"+voList);
        return 0;
    }
    public static <Element extends Structure> List<Element> pointer2Structure(Pointer pParam, Class<Element> res,int arraySize)
    {

        List<Element> list = new ArrayList<>();
        for (int k=0;k<arraySize;k++){

            try {
                Element Param = res.newInstance();
                Pointer facePointer = Param.getPointer();
                byte[] byteArray = pParam.getByteArray(Param.size()*k, Param.size());
                facePointer.write(0,byteArray,0,Param.size());
                Param.read();
                list.add(Param);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        return list;
    }
    /**
     * byte[]转int
     * @param bytes
     * @return
     */
    public static int byteArrayToInt(byte[] bytes) {
        int value = 0;
        // 由高位到低位
        for (int i = 0; i < 4; i++) {
            int shift = (4 - 1 - i) * 8;
            value += (bytes[i] & 0x000000FF) << shift;// 往高位游
        }
        return value;
    }

}

c++如果自己实现回调,回调demo如下

//回调函数。 context 任意一个对象
static int OnCallbackFun(void* context, int linkStatus,TDELEMENT *pointArray,int size)
{
   if (size)
   {
      for (int index = 0; index < size; ++index)
      {
          TDELEMENT el = pointArray[index];
          
      }
   }
   return size;
}

4.指针数组对应的解析对象

package org.springblade.subway.vo.jnaTest;


import com.sun.jna.Structure;
import lombok.Data;
import lombok.ToString;

import java.util.ArrayList;
import java.util.List;

@Data
public class Element extends Structure {

    public int SubSystem;
    public byte[] Addr = new byte[16];
    public byte[] Value = new byte[16];

    public static class ByReference extends Element implements Structure.ByReference {}
    public static class ByValue extends Element implements Structure.ByValue {}

    @Override
    public List getFieldOrder(){
        List a = new ArrayList();
        a.add("SubSystem");
        a.add("Addr");
        a.add("Value");

        return a;
    }


}

vo对象

@Data
public class ElementVo {
    int SubSystem;
    String Addr;
    String Value;
}

5.最后说一下,启动函数里面使用了阻塞,让我的实例不挂掉

推荐阅读