参考资料:
https://blog.csdn.net/ctwy291314/article/details/82895604 Java JNA (三)—— 结构体使用及简单示例
https://www.jianshu.com/p/ead89497c403 JNA 教程
1.引入依赖
1
2
3
4
5
6<dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.5.0</version> </dependency>
2.存放DLL路径
2.1 项目中放在resource目录下
2.2 或者放在这目录下
2.3 打成jar包后,路径
1
2linux: /usr/lib/ win:所有DLL放同级目录
2.4 自定义路径
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public boolean addDllLocationToPath(String dllLocation) { try { System.setProperty("java.library.path", System.getProperty("java.library.path") + ";" + dllLocation); Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths"); fieldSysPath.setAccessible(true); fieldSysPath.set(null, null); } catch (Exception e) { System.err.println("Could not modify path"); return false; } return true; } }
3.继承library
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Platform; /** Simple example of JNA interface mapping and usage. */ public class HelloWorld { // This is the standard, stable way of mapping, which supports extensive // customization and mapping of Java to native types. public interface CLibrary extends Library { CLibrary INSTANCE = (CLibrary) Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class); void printf(String format, Object... args); } public static void main(String[] args) { CLibrary.INSTANCE.printf("Hello, Worldn"); for (int i=0;i < args.length;i++) { CLibrary.INSTANCE.printf("Argument %d: %sn", i, args[i]); } } }
4.数据类型映射
Java primitive types (and their object equivalents) map directly to the native C type of the same size.
Native Type | Size | Java Type | Common Windows Types |
char | 8-bit integer | byte | BYTE, TCHAR |
short | 16-bit integer | short | WORD |
wchar_t | 16/32-bit character | char | TCHAR |
int | 32-bit integer | int | DWORD |
int | boolean value | boolean | BOOL |
long | 32/64-bit integer | NativeLong | LONG |
long long | 64-bit integer | long | __int64 |
float | 32-bit FP | float | |
double | 64-bit FP | double | |
char* | C string | String | LPCSTR |
void* | pointer | Pointer | LPVOID, HANDLE, LPXXX |
Unsigned types use the same mappings as signed types. C enums are usually interchangeable with "int".
无符号类型的映射等同于有符号类型,如 unsigned short ->short ,枚举等同于int
5.结构体映射
1
2
3
4
5
6
7struct CodeData { unsigned char code[4096]; unsigned short codeLen; unsigned char orgId[8]; unsigned short orgIdLen; };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20@Structure.FieldOrder({"code", "codeLen", "orgId", "orgIdLen"}) public static class CodeData extends Structure { //二维码数据 4096,要和dll的大小一致 public byte[] code = new byte[4096]; // 二维码数据长度 4096 public short codeLen; //机构id public byte[] orgId; //机构id长度8 public short orgIdLen; //这个类代表结构体指针 public static class ByReference extends CodeData implements Structure.ByReference { } //这个类代表结构体本身 public static class ByValue extends CodeData implements Structure.ByValue { } }
注意事项:
1.Structure 子类中的公共字段的顺序,必须与C 语言中的结构的顺序一致。否则会报错!
2.C语言结构中的char数组指定了大小,则使用byte需要指定大小,不能使用String,原因我猜是因为内存块?
3.或者使用指针,初始化时指定大小
6.函数映射
1
2unsigned char getData (struct CodeData *code,unsigned char *str,unsigned short len, unsigned char *data,unsigned short *dataLen);
1
2
3
4
5
6
7
8
9
10
11
12/** * 获取数据 * * @param codeData 结构体指针入参 * @param str 字符串入参 * @param len 基础类型入参 * @param data 字符串出参 * @param dataLen 基础类型出参 * @return */ byte getData(CodeData.ByReference codeData,String str, short len, byte[] data, ShortByReference dataLen);
7.调用函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public static String getData() { String orgId = "12345678"; String code = "123456789"; String str = "test"; String len = 4; CtidLibrary.CodeData.ByReference codeData = new CtidLibrary.CodeData.ByReference(); codeData.orgId = orgId.getBytes(); codeData.orgIdLen = 8; byte[] codeTmp = code.getBytes(); for (int i = 0; i < codeTmp.length; i++) { codeData.code[i] = codeTmp[i]; } codeData.codeLen = (short) code.length(); byte[] data = new byte[1024]; ShortByReference dataLen = new ShortByReference(); byte resp = CtidLibrary.INSTANCE.getData(codeData, str, len, data, dataLen); System.out.println(resp); String result = new String(data); System.out.println(result); return result; }
注:出参和入参格式可能不一样
8.注意事项
1.dll库如果是32位的,JDK也要改成32位的。
2.dll存在依赖关系,先引入父级的依赖,具体如下:
2.1 依赖项
1
2
3public interface MklIntelThreadLibrary extends Library { MklIntelThreadLibrary INSTANCE = Native.load("mkl_intel_thread", MklIntelThreadLibrary.class); }
2.2 需要调用的dll
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public interface AntiSpoofLibrary extends Library { MklIntelThreadLibrary mkl = MklIntelThreadLibrary.INSTANCE; AntiSpoofLibrary INSTANCE = Native.load("AntiSpoof", AntiSpoofLibrary.class); /** * 初始化接口,返回:true正确,false错误 * * @return */ boolean InitSpoof(String modelPath); /** * 活体检测接口 ,返回:true 活体,false:假体 * * @return */ boolean AntiSpoofBase64(String rgbBase, String irBase, boolean print); }
3.Invalid memory access
可能原因:1.数据类型映射不对
2.不支持多线程,调用时需要使用同步代码块
最后
以上就是满意航空最近收集整理的关于SpringBoot 使用JNA 调用DLL过程以及遇到的问题总结的全部内容,更多相关SpringBoot内容请搜索靠谱客的其他文章。
发表评论 取消回复