简介
说明
java调用dll动态库的方法,总的有三种:JNI、JNA、JNative。其中JNA调用DLL是最方便的。java使用 JNI来调用dll动态库的调用,工作量略大,一般情况下开发人员会选用JNA或JNative。
使用JNative调用DLL除了要引入jar包外还需要额外引入一个dll文件,而JNA只需要引入jar即可使用。
官网
JNA API
数据对照
官网原版
C Type | Native Representation | Java Type |
char | 8-bit integer | byte |
wchar_t | platform-dependent | char |
short | 16-bit integer | short |
int | 32-bit integer | int |
int | boolean flag | boolean |
enum | enumeration type | int (usually) |
long long, __int64 | 64-bit integer | long |
float | 32-bit floating point | float |
double | 64-bit floating point | double |
pointer (e.g. void*) | platform-dependent (32- or 64-bit pointer to memory) | Buffer Pointer |
pointer (e.g. void*), array | 32- or 64-bit pointer to memory (argument/return) contiguous memory (struct member) | <P>[] (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 | ||
long | platform-dependent (32- or 64-bit integer) | NativeLong |
const char* | NUL-terminated array (native encoding or | String |
const wchar_t* | NUL-terminated array (unicode) | WString |
char** | NULL-terminated array of C strings | String[] |
wchar_t** | NULL-terminated array of wide C strings | WString[] |
void** | NULL-terminated array of pointers | Pointer[] |
struct* struct | pointer to struct (argument or return) (or explicitly) struct by value (member of struct) (or explicitly) | Structure |
union | same as | Union |
struct[] | array of structs, contiguous in memory | Structure[] |
void (*FP)() | function pointer (Java or native) | Callback |
pointer (<T> *) | same as | PointerType |
other | integer type | IntegerType |
other | custom mapping, depends on definition | NativeMapped |
指针
ByReference类有很多子类,这些类都非常有用
ByteByReference、DoubleByReference、FloatByReference、 IntByReference、LongByReference、 NativeLongByReference、PointerByReference、 ShortByReference、 W32API.HANDLEByReference、X11.AtomByReference、X11.WindowByReference
ByteByReference等类故名思议,就是指向原生代码中的字节数据的指针。
PointerByReference类表示指向指针的指针。
在JNA中模拟指针,最常用到的就是Pointer类和PointerByReference类。Pointer类代表指向任何东西的指针,PointerByReference类表示指向指针的指针。Pointer类更加通用,事实上PointerByReference类内部也持有Pointer类的实例。
示例
C Type | Java Type |
void * | Pointer |
void ** | PointerByReference |
char * | Pointer,ByteByReference |
char ** | PointerByReference |
char & | Pointer,ByteByReference |
int & | IntByReference |
int * | IntByReference |
JNA综述
其他网址
Java使用JNA方式调用DLL(动态链接库)(原创,装载请注明出处) - 简书
注意事项
如果dll/so通过x86平台编译,那么只能使用32位jdk环境加载,如果要使用64位jdk,必须使用x64平台编译。
定义接口
public interface Clibrary extends Library
定义加载dll库文件接口,继承自Library 或StdCallLibrary,默认的是继承Library,如果动态链接库里的函数是以stdcall方式输出的, 那么就继承StdCallLibrary,比如众所周知的kernel32库。
加载动态库
Clibrary INSTANCE = (Clibrary) Native.loadLibrary("VIDEOMP4LIB",Clibrary.class);
接口内部需要一个公共静态常量:INSTANCE,通过这个常量,就可以获得这个接口的实例,从而使用接口的方法,也就是调用外部dll/so的函数。该常量通过Native.loadLibrary()这个API函数获得,该函数有2个参数:
第一个参数
动态链接库dll/so的名称,但不带.dll或.so这样的后缀,这符合JNI的规范,因为带了后缀名就不可以跨操作系统平台了。
搜索动态链接库路径的顺序是:先从当前类的当前文件夹找,如果没有找到,再在工程当前文件夹下面找win32/win64文件夹,找到后搜索对应的dll文件,如果 找不到再到WINDOWS下面去搜索,再找不到就会抛异常了。
第二个参数
是本接口的Class类型。JNA通过这个Class类型,根据指定的.dll/.so文件,动态创建接口的实例。该实例由JNA通过反射自动生成。
接口中只需要定义你要用到的函数或者公共变量,不需要的可以不定义,注意参数和返回值的类型,应该和链接库中的函数类型保持一致。定义好接口后,就可以使用接口中的函数即相应dll/so中的函数了
如果本地类库不是线程安全的,可用
Clibrary INSTANCE2 = (Clibrary)Native.synchronizedLibrary("VIDEOMP4LIB",Clibrary.class);
JNA示例
引入依赖
implementation('net.java.dev.jna:jna:5.5.0')
将dll加入工程
32位dll或so:resources/win32-x86
64位dll或so:resources/win32-x86-64
定义接口与加载
假设本处有个Dll2x64.dll,里边有个加法函数:double Add(double a, double b);
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("Dll2x64", CLibrary.class);
double Add(double a, double b);
}
调用接口
public class Hello {
public static void main(String[] args) {
System.out.println(CLibrary.INSTANCE.Add(2, 3));
}
}
JNA结构体
必须写结构体成员的顺序及ByReference和ByValue
FieldOrder(
{"header", "deviceType"})
public class Device extends Structure {
public byte header; // 头部
public byte deviceType; // 设备类型
public static class ByReference extends Device implements Structure.ByReference{};
public static class ByValue extends Device implements Structure.ByValue{};
)
.
不写@Structrure.FieldOrder会报异常:finished with non-zero exit value 1
JNA问题解决
找不到指定模块
log
java.lang.UnsatisfiedLinkError: The specified module could not be found.
原因
缺少库,或者导入错了库
解决方法(补上缺少的库)
查看缺少的库:所用软件:Dependency Walker。此软件作用:
- 查看 PE 模块的导入模块。
- 查看 PE 模块的导入和导出函数。
- 动态剖析 PE 模块的模块依赖性。
用法
depends.exe=> File=> Open=> 选择的dll=> 若缺少,会报黄色感叹号(Error Opening file.系统找不到指定文件),例如:
可以搜索缺少的库,补到工程里。
其他
Exception in thread "main" java.lang.UnsatisfiedLinkError: %1 不是有效的 Win32 应用程序
jdk的位数与dll的位数不一致,换成一致的便可。
其他网址
JNA调用C语言动态链接库学习实践总结 第2页_Linux编程_Linux公社-Linux系统门户网站