当前位置:网站首页>【混合编程jni 】第十一篇之JNA详情
【混合编程jni 】第十一篇之JNA详情
2022-06-26 22:01:00 【华为云】
继续JNA的了解,如果你还不知道JNA是什么,可以看下我上篇文章
函数的映射
接口映射
通过 Native.load() 加载动态库的时候,直接通过接口对应动态库的函数,
因为JNA 会创建一个代理,代理 invoke通过Library.Handler. 在导出的方法表中找倒匹配的函数。
直接映射
JNA 提供了直接注册的方式,如果有原生的,被标注为 native的函数调用。
可以直接使用Native.register() 注册你的方法
数据类型映射
基础类型直接映射,因为大小相同
使用指针和数组
原始数组参数(包括结构)由它们对应的 Java 类型表示。例如:
//原始 C 声明 void fill_buffer ( int *buf, int len); void fill_buffer ( int buf[], int len); //与数组语法相同 //等效的 JNA 映射 void fill_buffer( int [] buf, int len);
注意:如果参数要由函数调用范围之外的本机函数使用,则必须使用 Memory 或 NIO 直接缓冲区。Java 原始数组提供的内存仅在函数调用期间由本机代码使用有效。
C 字符串数组(例如char* argv[]Cmain的 )可以用String[]Java 代码表示。JNA 将自动传递具有NULL最终元素的等效数组。
使用结构和联合
当函数需要指向结构的指针时,Java应该使用Structure。如果结构是按值传递或返回的,则只需对参数或返回类型类声明稍作修改即可。
定义类继承自Structure,。并且必须在FieldOrder注解或方法返回的列表中按顺序包含每个声明的字段名称getFieldOrder()。
如果函数需要结构数组(在内存中连续分配), Java 可以使用Structure[。
传入 的数组是Structure时,无需初始化数组元素(函数调用将为您分配、归零内存并分配元素)。
如果确实需要初始化数组,则应使用该Structure.toArray方法获取内存中连续的结构元素数组,然后可以根据需要对其进行初始化。
Unions 通常可以与Structures 互换,但要求您在setType方法正确传递给函数调用之前指示哪个联合字段是活动的。
如果您有特别长或复杂的结构,您可以考虑使用由 Olivier Chafik 编写的JNAerator工具,它可以为您生成 JNA 映射。
使用 ByReference 参数
当一个函数接受指向类型参数的指针时,您可以使用其中一种ByReference类型来捕获返回值,或子类化您自己的值。例如:
//原始 C 声明void allocate_buffer ( char **bufp, int * lenp);//等效的 JNA 映射void allocate_buffer(PointerByReference bufp, IntByReference lenp);
// UsagePointerByReference pref = new PointerByReference();IntByReference iref = new IntByReference();lib.allocate_buffer(pref, iref);Pointer p = pref.getValue();byte[] buffer = p.getByteArray(0, iref.getValue());
可以使用具有所需类型的单个元素的 Java 数组,但ByReference约定更好地传达了代码的意图。Pointer除了getByteArray()有效地作为类型转换到内存上之外,该类还提供了许多访问器方法。
PointerType可以通过从类派生来声明类型安全指针。
整点例子
1、数组 数组的例子,直接用上面的例子
c++头文件
#ifndef TESTJNA_TEST_H#define TESTJNA_TEST_H#define PDOOL_API extern "C" __declspec( dllexport )PDOOL_API int sum(int a, int b);PDOOL_API void fill_buffer(int buf[], int len);#endif //TESTJNA_TEST_H
c++ 实现
这里只是打印出所有的数组元素
#include "test.h"#include "iostream"int sum(int a ,int b){ return a +b;} void fill_buffer(int buf[], int len){ for (int i = 0;i<len;i++){ std::cout<<buf[i]; }}
将上面代码生成的dll 拷贝到java项目的resource目录,
如果不会的话可以看下我之前的文章
看下java侧的实现
import com.sun.jna.Library;import com.sun.jna.Native;/** * 动态库接口 * @author xin.chong */public interface Lib extends Library { Lib INSTANCE = Native.load( "testJNA.dll", Lib.class); int sum(int a,int b); void fill_buffer(int[] buf, int len);}
看下调用
/** * Hello world! * */public class App { public static void main(String[] args) { int result = Lib.INSTANCE.sum(1,3); System.out.println("恭喜,JNA 第一个程序成功 ,the result is "+ result); int[] arr = {1,2,3,4,5}; Lib.INSTANCE.fill_buffer(arr,arr.length); }}
看下打印结果
数组调用还是简单的,当然这只是基础类型的数组,复杂的后面会讲,继续!
2、结构体
结构体属于复杂的自定义结构,所以处理起来还是比较麻烦,下面一起看下在Java中如何模拟结构体的
c++ 侧 定义一个玩家结构体
#ifndef TESTJNA_TEST_H#define TESTJNA_TEST_H#define PDOOL_API extern "C" __declspec( dllexport ) struct PlayerStruct{ long id; wchar_t* name; int age;}; PDOOL_API int sum(int a, int b); PDOOL_API void fill_buffer(int buf[], int len); PDOOL_API void createPlayer(PlayerStruct* pUserStruct); #endif //TESTJNA_TEST_Hcpp 实现void createPlayer(PlayerStruct* pPlayerStruct){ std::cout<<pPlayerStruct->id <<" "<< pPlayerStruct->name <<" "<<pPlayerStruct->age;}
Java侧的实现
先创建一个类继承自 Structure 和 C++ 侧进行对应映射
import com.sun.jna.Structure; import java.util.Arrays;import java.util.List; public class PlayerStruct extends Structure { public long id; public String name; public int age; public static class ByReference extends PlayerStruct implements Structure.ByReference {} public static class ByValue extends PlayerStruct implements Structure.ByValue {} @Override protected List<String> getFieldOrder() { return Arrays.asList(new String[] { "id", "name", "age"}); }}
注意点:
必须要继承 Structure getFieldOrder 返回的字段列表要和C++侧保持一致,顺序不能乱,对应了c++ 侧的内存顺序 ByReference 对应c++侧的结构体指针 ByValue 是结构体的值
边栏推荐
- Is there any risk in opening a new bond registration account? Is it safe?
- 简述unity的模型动画功能
- 【图像处理基础】基于matlab GUI图像直方图均衡化系统【含Matlab源码 1924期】
- MacOS环境下使用HomeBrew安装[email protected]
- leetcode:141. Circular linked list [hash table + speed pointer]
- 这个算BUG吗?乱填的字母是否可以关闭
- Introduction of classic wide & deep model and implementation of tensorflow 2 code
- leetcode:141. 环形链表【哈希表 + 快慢指针】
- Hands on deep learning pytorch version 3 - Data Preprocessing
- Vulnhub's DC8
猜你喜欢
[solution] sword finger offer 15 Number of 1 in binary (C language)
在Flutter中解析复杂的JSON
DAST 黑盒漏洞扫描器 第五篇:漏洞扫描引擎与服务能力
【图像处理基础】基于matlab GUI图像直方图均衡化系统【含Matlab源码 1924期】
vulnhub之dc8
Leetcode (452) - detonate the balloon with the minimum number of arrows
Godson China Science and technology innovation board is listed: the market value is 35.7 billion yuan, becoming the first share of domestic CPU
Parsing complex JSON in fluent
YOLOv6:又快又准的目标检测框架开源啦
Web crawler 2: crawl the user ID and home page address of Netease cloud music reviews
随机推荐
LabVIEW Arduino tcp/ip remote smart home system (project part-5)
Unity3d plug-in anyportrait 2D bone animation
Introduction of classic wide & deep model and implementation of tensorflow 2 code
Homebrew installation in MacOS environment [email protected]
[leetcode]- linked list-2
Which securities company is the most convenient, safe and reliable for opening an account
【图像处理基础】基于matlab GUI图像直方图均衡化系统【含Matlab源码 1924期】
Using C to operate SQLSERVER database through SQL statement tutorial
random_normal_initializer 使用
美术向的Unity动画知识
SAP commerce cloud project Spartacus getting started
How to enable Hana cloud service on SAP BTP platform
在Flutter中解析复杂的JSON
【题解】剑指 Offer 15. 二进制中1的个数(C语言)
leetcode:141. Circular linked list [hash table + speed pointer]
Is this a bug? Whether the randomly filled letters can be closed
DLA model (classification model + improved segmentation model) + deformable convolution
Data governance does everything
DAST 黑盒漏洞扫描器 第五篇:漏洞扫描引擎与服务能力
Yolov6: un cadre de détection de cibles rapide et précis est Open Source