JNA使用总结
这两天工作有一项任务,需要用 java 去调用 c 语言编写的 SDK,用到了 JNA,用的过程中遇到了些问题,在这里总结下使用方法,记录下。
分为几个步骤:编写一个继承了 Library 的接口,在类中声明接口,编写结构体(如果有需要),调用接口。
1. 编写 Library 接口
在接口中声明的方法要和 SDK 的函数对应上,方法名要对应函数名。
参数的话,基本类型一样,指针对应 Pointer、XxxByReference,结构体的对应需要自定义 java 类。详情可以参见 https://yq.aliyun.com/articles/606236?utm_content=m_1000018939 中的表格。
调用接口时,使用 Native.loadLibrary("dll文件路径") 来生成一个代理对象,然后调用代理对象中的方法。
示例代码如下:
public interface ChengFengSDK extends Library { /** * 生成一个代理对象,后面使用时,需要调用 INTERFACE 中的接口,然后代理对象来调用 C 语言的实现。 */ ChengFengSDK INTERFACE = (ChengFengSDK) Native.loadLibrary("HieClientUnit", ChengFengSDK.class); /** * 接口声明,方法名和参数列表要与头文件的函数对应起来 */ int HieClient_UserLogin (WinNT.HANDLEByReference hUser, UserLoginPara.ByReference cUserLoginPara); int HieClient_Start(); int HieClient_Stop(); }
2. 自定义结构体
当函数的参数中存在结构体时,java 里需要自定义一个类来与之对应。
编写一个类,继承 Structure。
类中的属性与结构体中的属性要一一对应,并且全都要是 public 权限。
重写 getFieldOrder 方法,List 中的名称顺序要与函数的参数列表一致。
注意,如果函数中的参数为指针类型,则传入的结构体类需要继承 Structure.ByReference,否则会抛内存访问错误。
示例代码如下:
public class UserLoginPara extends Structure { public byte[] sServerIP = new byte[256]; public int dwCommandPort; public byte[] sUName = new byte[32]; public byte[] sUPass = new byte[32]; public int[] dwReserve = {0, 1}; // 如果是指针类型,用这个 public static class ByReference extends UserLoginPara implements Structure.ByReference { } public static class ByValue extends UserLoginPara implements Structure.ByValue { } protected List getFieldOrder() { return Arrays.asList(new String[]{"sServerIP", "dwCommandPort", "sUName", "sUPass", "dwReserve"}); } }
3. 调用接口
要注意,数组需要初始化,大小要与 C 语言中的大小一致。
示例代码如下:
WinNT.HANDLE hUserLogin = WinBase.INVALID_HANDLE_VALUE; WinNT.HANDLEByReference hUserLoginRef = new WinNT.HANDLEByReference(hUserLogin); //配置用户登录参数 UserLoginPara.ByReference tLoginPara = new UserLoginPara.ByReference(); tLoginPara.dwCommandPort = port; //端口 System.arraycopy(ip.getBytes(), 0, tLoginPara.sServerIP, 0, ip.getBytes().length); //ip System.arraycopy(userName.getBytes(), 0, tLoginPara.sUName, 0, userName.getBytes().length); //用户名 System.arraycopy(passwd.getBytes(), 0, tLoginPara.sUPass, 0, passwd.getBytes().length); //调用登录接口 nLoginCode = sdk.HieClient_UserLogin(hUserLoginRef, tLoginPara);
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· Ai满嘴顺口溜,想考研?浪费我几个小时
· Browser-use 详细介绍&使用文档
· 软件产品开发中常见的10个问题及处理方法