JNA 调用 DLL
JNA
JNA 即 Java Native Access,是一个开源框架,是基于JNI做的封装。主要用于调用C或C++的动态库,达到程序需要实现的效果。
与JNI不同,JNI需要根据java生成.h文件,然后生成对应的DLL,这样会破坏原有的动态库或者需要重新封装一次原有的DLL为新的DLL;JNA则只需要知道调用DLL的.h文件,根据头文件中定义的宏、函数等构造对应的java类和对象,实现Java程序调用已知DLL的效果。
实例阐释
现有已知的.h即头文件如下:
TEST_API.h:定义dll提供的方法;
#ifndef _TEST_API_H__
#define _TEST_API_H__#include "TestEntry.h"#ifndef TEST_API_EXPORTS
#define TESTFUN_API _declspec( dllimport )
#else
#define TESTFUN_API _declspec( dllexport )
#endif#define API_SUCC 0 // 成功
#define API_FAIL 1 // 失败typedef int (*TEST_Method1_Evt) (unsigned char code); // 初始化服务的回调,判断是否成功typedef int (*TEST_Method2_Evt) (unsigned int code, Test_Struct_Entry info, unsigned char finishFlag); // 获取所有用户的回调,获取C返回的用户结果// 定义回调函数指针
typedef struct
{TEST_Method1_Evt TestMethod1Ack;TEST_Method2_Evt TestMethod2Ack;
}TESTEVENTS, *PTESTEVENTS;//初始化服务
extern "C" TESTFUN_API int __stdcall TEST_OpenService(unsigned int IP,unsigned short Port,PTESTEVENTS events);//查看所有用户
extern "C" TESTFUN_API int __stdcall TEST_GetSystemUserAll(unsigned char LoginUser[USER_LEN]); // 登录的用户,后台用于注册校验,此处测试设置为admin#endif
TestEntry.h:定义上述函数使用的参数结构
#ifndef _TEST_H__
#define _TEST_H__#define USER_LEN 30
#define USER_HABBIT_LEN 30
#define USER_COUNT 50//用户信息
typedef struct Nm_User_ProfileInfo
{unsigned char UserName[USER_LEN]; // 用户名unsigned int UserAge; // 用户年龄unsigned char Habbit[USER_HABBIT_LEN]; // 用户爱好char Password[30]; // 用户密码
}User_ProfileInfo_Stru;//用户查询返回结果
typedef struct Test_User_Search_Rsp
{unsigned int Num;User_ProfileInfo_Stru User_Info[USER_COUNT];
}Test_Struct_Entry;#pragma pack(pop)
#endif
对应的java代码如下:
1.对外提供的方法定义
此处需要注意,32位的DLL和64位的DLL函数名字或许会不一样,可以使用工具Depenency Walker查看。
若此处定义的方法名和DLL里面的函数名不一致,则会导致查不到方法,进而报异常。
所以此处用UnionFunctionMapper 来进行方法名的映射。
public interface TestLib extends StdCallLibrary { // C 中用__stdcall 定义的函数时,继承StdCallLibrary类//初始化服务public int TEST_OpenService(int ip, short port, TESTAckStruct callback);//查看所有用户public int TEST_GetSystemUserAll();class UnionFunctionMapper implements FunctionMapper {public String getFunctionName(NativeLibrary nativeLibrary, Method method) {if (Platform.is64Bit()) {//dll为64位时候,返回原函数名return method.getName();} else {//dll为32时,返回更改后的函数名,此处是因为32位的DLL函数名称或许和64位的不一样,可以使用Depenency Walker查看具体的名字// 若名字不一样,则会导致方法查不到,进而报异常HashMap<String, String> map = new HashMap<String, String>();map.put("TEST_OpenService", "_TEST_OpenService@12");map.put("TEST_GetSystemUserAll", "_TEST_GetSystemUserAll@0");String name = map.get(method.getName());return name == null ? method.getName() : name;}}}
}
2.TEST_OpenService方法使用的参数TESTAckStruct 构造
定义的参数必须为public类型,否则不会jna不会认。
field里面的顺序必须一致,不一致则会导致数据混乱。
public class TESTAckStruct extends Structure {public AckInterfaceCollection.TEST_Method1_Evt TestMethod1Ack;public AckInterfaceCollection.TEST_Method2_Evt TestMethod2Ack;protected List getFieldOrder() {List<String> list = new ArrayList<String>();list.add("TestMethod1Ack");list.add("TestMethod2Ack");return list;}
}
3.定义回调接口
public class AckInterfaceCollection {public interface TEST_Method1_Evt extends StdCallLibrary.StdCallCallback{int TestMethod1Ack(char code);}public interface TEST_Method2_Evt extends StdCallLibrary.StdCallCallback{int TestMethod2Ack(int code, EntryCollection.Test_Struct_Entry info, char finishFlag);}}
4.参数结构化,对应的结构即为TestEntry.h中定义的结构;
ByReference 是用于指针
ByValue是用于值
定义的参数必须为public,getFieldOrder方法中加入list中的数目和定义的public变量的必须一致,否则会报错。
public class EntryCollection {private final static int USER_LEN = 30;private final static int USER_HABBIT_LEN = 30;private final static int USER_COUNT = 50;public static class User_ProfileInfo_Stru extends Structure {public byte[] UserName = new byte[USER_LEN]; // 用户名public int UserAge; // 用户年龄public byte[] Habbit = new byte[USER_HABBIT_LEN]; // 用户爱好public byte[] Password = new byte[30]; // 用户密码@Overrideprotected List getFieldOrder() { // 顺序与上述定义的顺序必须一致,名字也必须一样List<String> field = new ArrayList<String>();field.add("UserName");field.add("UserAge");field.add("Habbit");field.add("Password");return field;}public static class ByReference extends User_ProfileInfo_Stru implements Structure.ByReference {}public static class ByValue extends User_ProfileInfo_Stru implements Structure.ByValue {}}public static class Test_Struct_Entry extends Structure {public int Num;public User_ProfileInfo_Stru[] User_Info = new User_ProfileInfo_Stru[USER_COUNT];@Overrideprotected List getFieldOrder() {List<String> field = new ArrayList<String>();field.add("Num");field.add("User_Info");return field;}public static class ByReference extends Test_Struct_Entry implements Structure.ByReference {}public static class ByValue extends Test_Struct_Entry implements Structure.ByValue {}}}
5.加载动态库文件
public class Operation {protected TestLib testLib;public void setNmsLib() {String libPath = "testlib/TEST_API";if (!Platform.is64Bit()){libPath = "testlib32/TEST_API";}Map<String, Object> options = new HashMap<>();options.put(Library.OPTION_FUNCTION_MAPPER, new TestLib.UnionFunctionMapper());TestLib testLib= (TestLib) Native.loadLibrary(libPath, TestLib.class, options);this.testLib = testLib;}}
6.定义的回调的具体实现
public class AckImpl extends TESTAckStruct {public class TestMethod1Ack implements AckInterfaceCollection.TEST_Method1_Evt {@Overridepublic int TestMethod1Ack(char code) {System.out.println("==========" + code);// TODO: 根据自己需要处理返回值return 0;}}public class TestMethod2Ack implements AckInterfaceCollection.TEST_Method2_Evt{@Overridepublic int TestMethod2Ack(int code, EntryCollection.Test_Struct_Entry info, char finishFlag) {System.out.println("===Code:" + code + "===Info:" + info + "=== finishFlag:" + finishFlag);// TODO: 根据自己需要处理返回值return 0;}}}
7.调用C的方法
public class Test extends Operation {public void openService(int ip, short port) {TESTAckStruct ackStruct = new TESTAckStruct();AckImpl impl = new AckImpl();ackStruct.setTestMethod1Ack(impl.new TestMethod1Ack()); // 设置回调的具体实现ackStruct.setTestMethod2Ack(impl.new TestMethod2Ack());setNmsLib();testLib.TEST_OpenService(ip, port, ackStruct);}public void getSystemUserAll(String user) {if (testLib == null) {setNmsLib();}testLib.TEST_GetSystemUserAll(user);}}
【本章完,后续介绍jna常见的问题以及原因:附上链接 https://blog.csdn.net/m0_37725100/article/details/93998879 】
欢迎关注与指教…
JNA 调用 DLL相关推荐
- JNA调用DLL函数遇到的几个问题
最近一个JSP项目需要用到分词模块,而分词模块实用C++写成的DLL库.于是上网搜各种方法,最后选择了JNA作为JSP调用DLL的工具. JNA(Java Native Access )提供一组Jav ...
- 使用Jna调用dll函数库(java使用jna对接硬件接口)
记录一次项目经历,新公司开发过程中遇到了硬件对接的需求,没有接触过这方面的我一想到这些就很头大,花了几天时间来专门研究一下这个.一般硬件购买后厂家都会附赠一些开发文档,有各种语言的demo,里面其实重 ...
- JNA调用dll - java集成一美IP对讲SDK(dll文件)
项目需要集成一美IP对讲机,一美SDK是dll文件,其他的dll文件集成做法也类似.记录一下 准备 将一美SDK文件的DataTran.dll文件放到系统C:\Windows\System32文件夹里 ...
- 使用Java中的jna调用dll
简介: 在我们日常编码中在与硬件通信或者与其他的c++平台通信的时候经常用java调用dll文件,下面我们介绍俩种使用jna调用dll的方式. 如果是自己部门写的dll文件,一般会有头文件,头文件中会 ...
- java中通过JNA调用dll
---恢复内容开始--- 1. JNA简单介绍 先说JNI(Java Native Interface)吧,有过不同语言间通信经历的一般都知道,它允许Java代码和其他语言(尤其C/C++)写的代码进 ...
- java library jna_Java JNA 调用dll库
JNA JNA(Java Native Access )提供一组Java工具类用于在运行期间动态访问系统本地库(native library:如Window的dll)而不需要编写任何Native/JN ...
- Java用JNA调用dll : Invalid memory access
问题描述 java通过JNA调用C/C++ dll时,报Invalid memory access 问题原因 经过分析原因是数据类型不匹配问题 int &a 和 a 的区别 C语言中的a是一个 ...
- java jna调用dll文件_关于java jna调用dll的问题
public interface User32 extends StdCallLibrary { User32 INSTANCE = (User32)Native.loadLibrary(" ...
- java web argox打印机 用jna调用dll
打印机 型号:X-1000VL 用的是PPLB 环境是windowsX64 eclipse jdk1.8(64位) jar包 jna-4.2.2..jar dll : WinPort.dll ,Win ...
最新文章
- EasyJWeb-Velocity脚本简明教程
- spinbox 上下箭头事件_[React] 3 - 自动绑定 (事件绑定)
- 马化腾内部分享:三个问题说透如何做产品
- faster_rcnn c++版本的 caffe 封装(1)
- java中数值023是什么类型_【Java 教程(原创)】023.参数传值——引用类型参数的传值...
- 聊聊高并发(二十四)解析java.util.concurrent各个组件(六) 深入理解AQS(四)
- 管道( Pipeline )模型--示例
- DCMTK3.5.4与3.6.0版本的区别
- 德州扑克AI--Programming Poker AI(译)
- 游戏开发之类和对象的基本概念(C++基础)
- 区块链 Fisco bcos 智能合约(13)-Solidity的设计模式
- 如何使用U盘制作Windows 7安装盘
- html app5 仿微信朋友圈,uniapp仿微信聊天App界面|仿微信朋友圈|uniapp仿微信
- 购买周期 python-用Python实现一个基于EG协整法的跨周期套利策略
- GD32F103串口DMA收发
- 微信小程序即时聊天前后端(TP5+Gateway)
- 利用xiaopiu做产品原型输出与交互设计
- 一个3D城市地图应用开发工具,等你获取 ThingJS 3D 全景 可视化
- 小米微信自动加好友appium
- Qt之Windows下禁用中文输入法