JNA 实际开发中若干问题解决方法

简介: JNA 实际开发中若干问题解决方法

JNA 实际开发中若干问题解决方法

很早就已经听说过 JNI(Java Native Interface)Java 本地接口,奈何调用本地动态链接库太过于复杂,就一直没有再尝试。而最近因为工作需要调用 Windows DLL 动态链接库(对应 Linux 中 so 文件),而对 JNA 有了入坑体验,对实际工作中遇到的问题做出总结。

1. 调用 Windows 窗口打印Hello World

  1. pom 依赖
<dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna</artifactId>
            <version>latest</version>
        </dependency>
  1. JNA 在加载驱动时提供两种加载方式 , 直接映射接口生成

接口生成

public interface HelixcsDll extends StdCallLibrary {
   
        // loadLibary 为动态链接库加载目录
        HelixcsDll HELIXCS_DLL = Native.loadLibrary("helixcs.dll", HelixcsDll.class);
        // 在 dll 中存在相同 SomeFunction 的函数 
        void SomeFunction(String content);
    }

    // 调用
    HelixcsDll.HELIXCS_DLL.SomeFunction("Hello World");

直接映射

class Helixcs{
   
        static {
   
            Native.register("helixcs.dll");
        }
        // 映射为本地方法
        public static  native void SomeFunction(String content);

        public static void main(String[] args) {
   
            SomeFunction("Hello World");
        }
    }

2. C 类型和 Java 类型映射。

  1. JNA 官方提供的默认类型映射

Default Type Mappings 默认类型映射

Java primitive types (and their object equivalents) map directly to the native C type of the same size.

Java 原始类型以相同的大小映射 C 类型。


Native TypeSizeJava TypeCommon Windows Types
char8-bit integerbyteBYTE, TCHAR
short16-bit integershortWORD
wchar_t16/32-bit charactercharTCHAR
int32-bit integerintDWORD
intboolean valuebooleanBOOL
long32/64-bit integerNativeLongLONG
long long64-bit integerlong__int64
float32-bit FPfloat
double64-bit FPdouble
char C string String LPTCSTR
voidpointerPointerLPVOID, HANDLE, LP XXX

未签名类型作为签名类型来映射。 C 中枚举类型可替换为 “int”。

Unsigned types use the same mappings as signed types. C enums are usually interchangeable with "int".

3. 官方提供的详细的类型映射

Marshalling/Unmarshalling (Java/Native Type Conversions)



C Type Native Representation Java Type
char8-bit integerbyte
wchar_tplatform-dependentchar
short16-bit integershort
int32-bit integerint
intboolean flagboolean
enumenumeration typeint (usually)
long long, __int6464-bit integerlong
float32-bit floating pointfloat
double64-bit floating pointdouble
pointer (e.g. void ) platform-dependent (32- or 64-bit pointer to memory) Buffer


pointer (e.g. void),
array32- or 64-bit pointer to memory (argument/return)
contiguous memory (struct member)

[] (array of primitive type)


In addition to the above types, which are supported at the native layer, the JNA Java library automatically handles the following types. All but NativeMapped and NativeLong are converted tobefore being passed to the native layer.
longplatform-dependent (32- or 64-bit integer)
const char NUL-terminated array (native encoding or jna.encoding) String
const wchar_tNUL-terminated array (unicode)
char NULL-terminated array of C strings String[]
wchar_tNULL-terminated array of wide C strings
void * NULL-terminated array of pointers
struct
structpointer to struct (argument or return)
struct by value (member of struct) ()
unionsame as Structure
struct[]array of structs, contiguous in memory
void ( FP)() function pointer (Java or native)
pointer ( )same as Pointer
otherinteger type
othercustom mapping, depends on definition

4. 经验总结默认映射关系

尽管 JNA 官方已经提供了详细的类型映射文档。但在实际中发现按照官方映射可能出现莫名问题。对此我们在实际开发中对于一些类型的映射报错,可以参考以下映射做出调整。

C类型 JNA类型 说明
char * out Pointer Pointer room = new Memory(30);
uchar * out Pointer Pointer room = new Memory(30);
long * long [ ]
int * init [ ]
int int
char * byte [ ]
char * argv[] String []
uchar int
long NativeLong 兼容 32和64位

5. 常见错误

1. UnsatisfiedLinkError 问题

存在多个动态链接库之间调用情况,可能缺少其中某一个动态链接库文件。

2. Error Memory Access 问题

较大情况下存在参数类型映射错误,参考 JNA 类型映射。

3. dll can not find in win32/86

无法加载到动态链接库文件路径,需要将动态链接库放到项目根目录下,推荐开启 JNA 驱动加载 debug 模式,

System.setProperty("jna.debug_load", "true");

手动指定动态链接库文件路径

System.setProperty("jna.library.path",dllResourcePath);
System.setProperty("jna.platform.library.path",dllResourcePath);

4. 程序在运行一段时间后崩溃

在JNA crash-protection 中,官方文档说明的崩溃的主要原因,( These are often caused by improper mappings or invalid arguments passed to the native library.) 未知的参数类型映射导致vm崩溃。在很大程度上使用 Pointer 来作为 Java 通用映射类型。
而 JNA 默认程序保护Native.setProtected(true)使得 java 错误来代替程序崩溃,可以设置 Native.setProtected(false) 来 dump 出崩溃日志。

问题可以反馈到 JNA Google Group : https://groups.google.com/forum/#!forum/jna-users

6. 参考

  1. JNA Google Group : https://groups.google.com/forum/#!forum/jna-users

  2. JNA API Documentation: https://java-native-access.github.io/jna/4.2.1/overview-summary.html

  3. JNA VM Crashed Protection :http://java-native-access.github.io/jna/4.5.1/javadoc/overview-summary.html#crash-protection

目录
相关文章
|
8月前
|
存储 设计模式 Java
深入 Python 解释器源码,我终于搞明白了字符串驻留的原理!
深入 Python 解释器源码,我终于搞明白了字符串驻留的原理!
102 2
|
8月前
|
安全 Java
从零开始学习 Java:简单易懂的入门指南之不可变集合、方法引用(二十六)
从零开始学习 Java:简单易懂的入门指南之不可变集合、方法引用(二十六)
|
5月前
|
Java 开发者
别再傻傻分不清!Java if-else与switch的性能对比全解析!
别再傻傻分不清!Java if-else与switch的性能对比全解析!
109 1
|
5月前
|
Java
Java 新手入门:重载和重写傻傻分不清?一篇文章带你清晰理解!
Java 新手入门:重载和重写傻傻分不清?一篇文章带你清晰理解!
47 0
Java 新手入门:重载和重写傻傻分不清?一篇文章带你清晰理解!
|
7月前
|
SQL 前端开发 Java
2024考古之还在用原始JDBC开发 手搓 案例 实现一个模块的增删改
2024考古之还在用原始JDBC开发 手搓 案例 实现一个模块的增删改
47 0
|
算法 编译器 C语言
算法小白的心得笔记:分清楚执行程序和动态链接库的编译方式。
-fPIC 选项:这个选项告诉编译器生成位置无关代码(Position Independent Code)。这种代码同样可以在内存的任何位置执行,因为它使用的是相对地址而不是绝对地址。这对于动态库是必要的,因为动态库在被加载时,其在内存中的位置是不确定的。
51 0
|
存储 移动开发 Java
Java的第十四篇文章——文件和IO流(后期再学一遍)
Java的第十四篇文章——文件和IO流(后期再学一遍)
|
前端开发 Java 编译器
Java的第十六篇文章——枚举、反射和注解(后期再学一遍)
Java的第十六篇文章——枚举、反射和注解(后期再学一遍)
|
存储 Java
Java包装类基本知识
Java包装类基本知识
84 0
|
存储 缓存 安全
《深入理解Java虚拟机》读书笔记(六)--HotSpot的算法细节实现
《深入理解Java虚拟机》读书笔记(六)--HotSpot的算法细节实现
240 0
《深入理解Java虚拟机》读书笔记(六)--HotSpot的算法细节实现