首页 > 其他分享 >JNA使用指南

JNA使用指南

时间:2023-01-18 21:45:04浏览次数:59  
标签:arr int void ByReference JNA new 使用指南 public

JNA

JNA是建立在JNI技术基础之上的一个Java类库,它使您可以方便地使用java直接访问c/c++动态链接库中的函数。 相对于JNI, JNA大大简化了调用本地方法的过程,使用很方便,基本上不需要脱离Java环境就可以完成。(但是JNA无法完全替代JNI, JNA只能实现Java访问C/C++函数,作为一个Java框架,自然不能实现C语言调用Java代码, 此时,你还是需要使用JNI技术。

Maven依赖

    <dependencies>
        <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna</artifactId>
            <version>5.12.1</version>
        </dependency>
    </dependencies>

参数传递与处理

数据类型对应关系

官方文档: Overview (JNA API) (java-native-access.github.io)

C/C++ type java type description
char byte 8-bit
wchar_t char 16/32-bit
short short 16-bit
int int 32-bit
long/_int64 long 64-bit
long long long 64-bit
float float 32-bit
double double 32-bit
pointer(指针) Pointer
pointer array(指针数组) [ ] (数组)
char* String
char** String[]
void* Pointer
void** PointerByReference
int& IntByReference
int* (指向单个) IntByReference
struct Structure
(*fp)() (函数指针) Callback 一般用于回调函数

代码实战

C/C++层实现动态库

头文件声明

#ifndef ADAPTER_LIBRARY_H
#define ADAPTER_LIBRARY_H

#ifndef EXPORT_DLL
#define EXPORT_DLL __declspec(dllexport) //导出dll声明
#endif

struct Point {
    int x;
    int y;
};

struct DataPtr {
    int size;
    int *arr;
    char *str;
};

struct DataArray {
    int intArr[3];
    char charArr[3];
};

struct DataInf {
    DataPtr *data;
};

extern "C" {
EXPORT_DLL void GetDataStr(Point points[], int n);
EXPORT_DLL void GetDataPtrStr(DataPtr &dataPtr);
EXPORT_DLL  void GetDataArrayString(DataArray *dataArray);
EXPORT_DLL void GetDataInfStr(DataInf &dataInf);
}


extern "C" {
EXPORT_DLL void GetArrSum(int *arr, int n, int &ret);
// 将arr赋值, 返回
EXPORT_DLL void getArrBack(int *arr, int n);
EXPORT_DLL void PrintStrArr(char *str);
}

/**
 * 回调函数
 */
typedef void (*ProcessCallback)(char *host, int port);

ProcessCallback processCallback;

typedef void (*MessageCallback)(char *);

MessageCallback messageCallback;
extern "C" {
EXPORT_DLL void registerCallBack(ProcessCallback callback1, MessageCallback callback2);
EXPORT_DLL void invokeProcessCallBack(char *host, int port, char *str);
}

#endif //ADAPTER_LIBRARY_H

具体实现

#include "library.h"
#include <string>
#include <iostream>

EXPORT_DLL void GetDataStr(Point points[], int n) {
    std::string str = "{";
    for (int i = 0; i < n; ++i) {
        str += "[" + std::to_string(points[i].x) + "," + std::to_string(points[i].y) + "]";
    }
    str += "}";
    std::cout << "points = " << str << std::endl;
}

EXPORT_DLL void GetDataPtrStr(DataPtr &dataPtr) {
    int n = dataPtr.size;
    std::string str;
    for (int i = 0; i < n; ++i) {
        str += std::to_string(dataPtr.arr[i]) + dataPtr.str[i] + "%";
    }
    std::cout << "str = " << str << std::endl;
}

EXPORT_DLL  void GetDataArrayString(DataArray *dataArray) {
    int n = sizeof(dataArray->charArr) / sizeof(char);
    std::string str;
    for (int i = 0; i < n; ++i) {
        str += std::to_string(dataArray->intArr[i]) + dataArray->charArr[i] + "%";
    }
    std::cout << "str = " << str << std::endl;
}

EXPORT_DLL void GetDataInfStr(DataInf &dataInf) {
    int n = dataInf.data->size;
    std::string str;
    for (int i = 0; i < n; ++i) {
        str += std::to_string(dataInf.data->arr[i]) + dataInf.data->str[i] + "%";
    }
    std::cout << "str = " << str << std::endl;
}

EXPORT_DLL void GetArrSum(int *arr, int n, int &ret) {
    for (int i = 0; i < n; ++i) {
        ret += arr[i];
    }
}

EXPORT_DLL void getArrBack(int *arr, int n) {
    for (int i = 0; i < n; ++i) {
        arr[i] = i;
    }
    std::cout << "get " << n << " data" << std::endl;
}

EXPORT_DLL void PrintStrArr(char *str) {
    std::cout << str << std::endl;
}

EXPORT_DLL void registerCallBack(ProcessCallback callback1, MessageCallback callback2) {
    processCallback = callback1;
    messageCallback = callback2;
    std::cout << "call back function register successfully" << std::endl;
}

EXPORT_DLL void invokeProcessCallBack(char *host, int port, char *str) {
    std::cout << "connect successfully to:" << host << ":" << port << std::endl;
    processCallback(host, port);
    messageCallback(str);
}

之后编写CMakeLists.txt

cmake_minimum_required(VERSION 3.19)
project(adapter)

set(CMAKE_CXX_STANDARD 17)

add_library(adapter SHARED library.cpp)

java层调用

结构体定义

(同名与否无所谓)

Point

public class Point extends Structure {
    public int x;

    public int y;

    public Point() {

    }

    public Point(int a, int b) {
        this.x = a;
        this.y = b;
    }

    public static class ByReference extends Point implements Structure.ByReference {
        public ByReference(int a, int b) {
            this.x = a;
            this.y = b;
        }
    }

    public static class ByValue extends Point implements Structure.ByValue {
        public ByValue(int a, int b) {
            this.x = a;
            this.y = b;
        }
    }

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("x", "y");
    }
}

DataArray

public class DataArray extends Structure {
   public int[] intArr = new int[3];
   public byte[] bytesArr = new byte[3];
    public static class ByReference extends DataArray implements Structure.ByReference {
    }

    public static class ByValue extends DataArray implements Structure.ByValue {
    }

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("intArr","bytesArr");
    }
}

DataInf

public class DataInf extends Structure {
   public DataPtr.ByReference dataPtr;

    public static class ByReference extends DataInf implements Structure.ByReference {
    }

    public static class ByValue extends DataInf implements Structure.ByValue {
    }

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("dataPtr");
    }
}

DataPtr

import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;

public class DataPtr extends Structure {
    public int size;

    public Pointer intArrPtr;

    public Pointer byteArrPtr;

    public static class ByReference extends DataPtr implements Structure.ByReference {
    }

    public static class ByValue extends DataPtr implements Structure.ByValue {
    }

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("size","intArrPtr","byteArrPtr");
    }
}

DLL导入与同名接口

public interface CLibrary extends Library {
    CLibrary INSTANCE = Native.load("D:\\Files\\Code\\JNA\\adapter\\cmake-build-release\\libadapter.dll", CLibrary.class);

    void GetDataStr(Point[] data, int n);
    void GetDataArrayString(DataArray.ByReference data);

    void GetDataPtrStr(DataPtr.ByReference data);

    void GetDataInfStr(DataInf.ByReference data);

    void GetArrSum(int[] arr, int len, IntByReference ret);

   void getArrBack(int[] arr, int len);

    void PrintStrArr(String str);

    /**
     * 回调函数
     */
    void registerCallBack(Callback callback1,Callback callback2);

    void invokeProcessCallBack(String host, int port,String str);
}

调用测试

public class Main {
    public static void main(String[] args) {
        test1();
    }

    static void test1() {
        int n = 2;
        Point[] points = (Point[]) new Point().toArray(n);
        points[0].x = 1;
        points[0].y = 2;
        points[1].x = 3;
        points[1].y = 4;
        CLibrary.INSTANCE.GetDataStr(points, n);
    }

    static void test2() {
        DataArray.ByReference data = new DataArray.ByReference();
        data.intArr = new int[]{5, 6, 7};
        data.bytesArr = new byte[]{'a', 'b', 'c'};
        CLibrary.INSTANCE.GetDataArrayString(data);
    }

    static void test3() {
        int size = 5;
        int[] arr = {1, 2, 3, 4, 5};
        byte[] bytes = {'a', 'b', 'c', 'd', 'e'};
        DataPtr.ByReference data = new DataPtr.ByReference();
        data.size = size;
        data.intArrPtr = new Memory(size * Native.getNativeSize(int.class));
        data.intArrPtr.write(0, arr, 0, size);
        data.byteArrPtr = new Memory(size * Native.getNativeSize(byte.class));
        data.byteArrPtr.write(0, bytes, 0, size);
        CLibrary.INSTANCE.GetDataPtrStr(data);
    }

    static void test4() {
        int size = 4;
        int[] arr = {1, 3, 1, 4,};
        byte[] bytes = {'l', 'o', 'v', 'e'};
        DataPtr.ByReference dataPtr = new DataPtr.ByReference();
        dataPtr.size = size;
        dataPtr.intArrPtr = new Memory(size * Native.getNativeSize(int.class));
        dataPtr.intArrPtr.write(0, arr, 0, size);
        dataPtr.byteArrPtr = new Memory(size * Native.getNativeSize(byte.class));
        dataPtr.byteArrPtr.write(0, bytes, 0, size);

        DataInf.ByReference dataInf = new DataInf.ByReference();
        dataInf.dataPtr = dataPtr;


        CLibrary.INSTANCE.GetDataInfStr(dataInf);

        Native.free(Pointer.nativeValue(dataPtr.intArrPtr));
        Pointer.nativeValue(dataPtr.intArrPtr, 0);

        Native.free(Pointer.nativeValue(dataPtr.byteArrPtr));
        Pointer.nativeValue(dataPtr.byteArrPtr, 0);
    }

    static void test5() {
        int[] arr = {1, 3, 1, 4, 5, 2, 0};
        String str = "love you";
        IntByReference ret = new IntByReference();
        CLibrary.INSTANCE.GetArrSum(arr, arr.length, ret);
        System.out.println("sum:" + ret.getValue());
        CLibrary.INSTANCE.PrintStrArr(str);
    }

    static void test6() {
        int[] arr = new int[5];
        CLibrary.INSTANCE.getArrBack(arr, arr.length);
        System.out.println(Arrays.toString(arr));
    }

    static void test7() {
        interface ProcessFunc extends Callback {
            void connect(String host, int port);
        }

        interface MessageFunc extends Callback {
            void msgPass(String str);
        }
        ProcessFunc processFunc = (host, port) -> System.out.println("connect to server " + host + ":" + port);
        MessageFunc messageFunc = (str) -> System.out.println(str + " pang");


        CLibrary.INSTANCE.registerCallBack(processFunc, messageFunc);
        CLibrary.INSTANCE.invokeProcessCallBack("127.0.0.1", 8888, "ping");
    }

test7执行结果:

call back function register successfully
connect successfully to:127.0.0.1:8888
connect to server 127.0.0.1:8888
ping pang

重点总结

回调函数:

  • C/C++:​ typedef void (*MessageCallback)(char *) ​​定义函数指针

  • java层: 继承接口JNA的Callback接口, 注册回调函数, 调用回调函数实体

typedef void (*ProcessCallback)(char *host, int port);

ProcessCallback processCallback;   // 回调函数名为processCallback

Cpp层调用:

  processCallback(host, port);

结构体数组

java中定义结构体数组: Point[] points = (Point[]) new Point().toArray(n);

Memory与free

当对象不再被任何对象引用时,GC会调用该对象的finalize()方法. Memory中finalize方法如下:

 /** Properly dispose of native memory when this object is GC'd. */
    @Override
    protected void finalize() {
        dispose();
    }
 
    /** Free the native memory and set peer to zero */
    protected synchronized void dispose() {
        try {
            free(peer);
        } finally {
            peer = 0;
            allocatedMemory.remove(this);
        }
    }
 
 protected static void free(long p) {
        // free(0) is a no-op, so avoid the overhead of the call
        if (p != 0) {
            Native.free(p);
        }
    }

new memory申请内存, 对象被GC(回收)会释放申请的内存, 前提是执行了GC, 为避免过多分配导致内存不足, 可手动释放内存, 方法为:

Pointer p = new Memory(1024 * 1024);
long ptr = Pointer.nativeValue(p);
Native.free(ptr);      //手动释放内存
Pointer.nativeValue(p, 0);  //peer置为0, 避免Memory对象被GC时重复执行Nativ.free()方法

标签:arr,int,void,ByReference,JNA,new,使用指南,public
From: https://www.cnblogs.com/shmilyt/p/17060637.html

相关文章

  • 华为云代码检查插件(CloudIDE版本)使用指南
    华为云代码检查插件(CloudIDE版本)使用指南​CodeCheck代码检查插件​感兴趣的小伙伴,可以试试使用我们的CodeCheck代码检查插件:CodeCheck代码检查插件免费体验​CloudIDE插件......
  • 界面控件DevExtreme中文使用指南——如何在应用中更好的使用图标库?
    DevExtreme拥有高性能的HTML5/JavaScript小部件集合,使您可以利用现代Web开发堆栈(包括React,Angular,ASP.NETCore,jQuery,Knockout等)构建交互式的Web应用程序,该套件附带功能......
  • Polygon 使用指南
    可能更好的阅读体验开坑!试图投日报.jpgI简介Polygon是一个多人合作的一个专门用于算法竞赛题目准备的网站。CodeForces、ICPC必需使用Polygon进行题目的准备。注......
  • QFramework v1.0 使用指南 工具篇:15. 补充内容:GridKit 二维格子数据结构
    在做游戏的过程中,我们经常需要处理二维格子类的数据,比如消除类游戏、俄罗斯方块、各种棋类游戏,还有我们最常用的Tilemap的地块数据,这些都需要二维格子数据结构。而在Ga......
  • 版本控制工具GIT使用指南
    前言:git是分布式版本控制系统,由linux创始人亲自设计,目前是最广泛使用的版本控制工具。本文介绍了版本控制系统的发展和GIT历史,并针对GIT安装和常用命令给出了试验。最后还列......
  • 字符流使用指南
    当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为......
  • ant使用指南详细入门教程
    一、概述ant是一个将软件编译、测试、部署等步骤联系在一起加以自动化的一个工具,大多用于Java环境中的软件开发。在实际软件开发中,有很多地方可以用到ant。开发环境:复制代......
  • 字节流使用指南
    一切皆为字节一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时......
  • B/S端界面控件DevExtreme中文使用指南——如何自定义图标
    DevExtreme拥有高性能的HTML5/JavaScript小部件集合,使您可以利用现代Web开发堆栈(包括React,Angular,ASP.NETCore,jQuery,Knockout等)构建交互式的Web应用程序,该套件附带功能......
  • 双向端口inout端口的使用指南
    在查阅了各种书和帖子之后,总结了以下inout端口的使用注意事项。(以下资料来源:《XilinxFPGA开发实用教程第二版》https://www.cnblogs.com/sea-wind/p/4924567.......