1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > Java通过JNA方式调用DLL(动态链接库)

Java通过JNA方式调用DLL(动态链接库)

时间:2024-04-09 04:10:58

相关推荐

Java通过JNA方式调用DLL(动态链接库)

1. JNA简单介绍

先说JNI(Java Native Interface)吧,有过不同语言间通信经历的一般都知道,它允许Java代码和其他语言(尤其C/C++)写的代码进行交互,只要遵守调用约定即可。首先看下JNI调用C/C++的过程,注意写程序时自下而上,调用时自上而下。

可见步骤非常的多,很麻烦,使用JNI调用.dll/.so共享库都能体会到这个痛苦的过程。如果已有一个编译好的.dll/.so文件,如果使用JNI技 术调用,我们首先需要使用C语言另外写一个.dll/.so共享库,使用SUN规定的数据结构替代C语言的数据结构,调用已有的 dll/so中公布的函 数。然后再在Java中载入这个库dll/so,最后编写Java native函数作为链接库中函数的代理。经过这些繁琐的步骤才能在Java中调用 本地代码。因此,很少有Java程序员愿意编写调用dll/.so库中原生函数的java程序。这也使Java语言在客户端上乏善可陈,可以说JNI是 Java的一大弱点!

JNA(Java Native Access)是一个开源的Java框架,是Sun公司推出的一种调用本地方法的技术,是建立在经典的JNI基础之上的一个框架。之所以说它是JNI的替 代者,是因为JNA大大简化了调用本地方法的过程,使用很方便,基本上不需要脱离Java环境加粗样式就可以完成。

如果要和上图做个比较,那么JNA调用C/C++的过程大致如下:

可以看到步骤减少了很多,最重要的是我们不需要重写我们的动态链接库文件,而是有直接调用的API,大大简化了我们的工作量。

JNA只需要我们写Java代码而不用写JNI或本地代码。功能相对于Windows的Platform/Invoke和Python的ctypes。

2. JNA技术原理

JNA使用一个小型的JNI库插桩程序来动态调用本地代码。开发者使用Java接口描述目标本地库的功能和结构,这使得它很容易利用本机平台的功能,而不会产生多平台配置和生成JNI代码的高开销。这样的性能、准确性和易用性显然受到很大的重视。

此外,JNA包括一个已与许多本地函数映射的平台库,以及一组简化本地访问的公用接口。

注意:JNA是建立在JNI技术基础之上的一个Java类库,它使您可以方便地使用java直接访问动态链接库中的函数。

原来使用JNI,你必须手工用C写一个动态链接库,在C语言中映射Java的数据类型。

JNA中,它提供了一个动态的C语言编写的转发器,可以自动实现Java和C的数据类型映射,你不再需要编写C动态链接库。

也许这也意味着,使用JNA技术比使用JNI技术调用动态链接库会有些微的性能损失。但总体影响不大,因为JNA也避免了JNI的一些平台配置的开销。

3. JNA简单使用

JNA把一个.dll/.so文件看做是一个Java接口,下面以一个简单的实例来说明怎么使用。

当然要从最经典的HelloWorld开始,我们调用C的printf函数打印出“HelloWorld”(官方的例子),前提是已将jar包加入你的classpath。

package com.sun.jna.examples;import 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, World\n");for (int i=0;i < args.length;i++) {CLibrary.INSTANCE.printf("Argument %d: %s\n", i, args[i]);}}}

运行程序 执行结果

需要定义一个接口,继承自Library 或StdCallLibrary默认的是继承Library ,如果动态链接库里的函数是以stdcall方式输出的,那么就继承StdCallLibrary,比如众所周知的kernel32库。比如上例中的接口定义:

public interface CLibrary extends Library {}

接口内部定义 接口内部需要一个公共静态常量:INSTANCE,通过这个常量,就可以获得这个接口的实例,从而使用接口的方法,也就是调用外部dll/so的函数。

CLibrary INSTANCE = (CLibrary)Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),CLibrary.class);

接口中只需要定义你要用到的函数或者公共变量,不需要的可以不定义,如上例只定义printf函数:void printf(String format, Object... args);注意参数和返回值的类型,应该和链接库中的函数类型保持一致。

调用链接库中的函数定义好接口后,就可以使用接口中的函数即相应dll/so中的函数了,前面说过调用方法就是通过接口中的实例进行调用,非常简单,如上例中:

CLibrary.INSTANCE.printf("Hello, World\n");for (int i=0;i < args.length;i++) {CLibrary.INSTANCE.printf("Argument %d: %s\n", i, args[i]);}

这就是JNA使用的简单例子,可能有人认为这个例子太简单了,因为使用的是系统自带的动态链接库,应该还给出一个自己实现的库函数例子

4. 使用Visual Studio创建一个自定义dll

Visual Studio 安装教程/pc915968220/article/details/100762195

创建动态链接库

添加一个头文件

编写两个接口和实践

#include "pch.h"extern "C" _declspec(dllexport) int add(int a, int b);int add(int a, int b){return a + b;}extern "C" _declspec(dllexport) int substract(int a, int b);int substract(int a, int b) {return a - b;}

点击调试按钮 在这里请注意 java的jdk版本是32位还是64位 需要和生成的dll文件一样

然后运行成功会控制台提示成功 然后去项目下拿到生成的dll文件

4. Java通过JNA方式调用DLL文件

pom文件依赖

<dependency><groupId>net.java.dev.jna</groupId><artifactId>jna</artifactId><version>4.5.2</version></dependency>

package XXX;import com.sun.jna.Library;import com.sun.jna.Native;public class TestDll {public interface DLibrary extends Library {//此处我的jdk版本为64位,故加载64位的DllDLibrary INSTANCE = (DLibrary) Native.loadLibrary("D:\\dll\\source\\repos\\Dll1\\x64\\Debug\\Dll1.dll",DLibrary.class);//Dll2x64中定义的函数int add(int a,int b);int substract(int a, int b);}public static void main(String[] args) {int add = DLibrary.INSTANCE.add(3,4);int substract = DLibrary.INSTANCE.substract(3,4);System.out.println("a+b="+add);System.out.println("a-b="+substract);}}

运行mian方法返回结果

到此java调用自定方法的dll文件完成 需要注意java定义接口的方法一定要和dll文件定义的方法名一样

再就是注意自己的jdk和dll文件生成的是32位还是64位 需要调用的DLL(注意JDK版本位数要与DLL一致)

4…Java和C的数据类型对照表

Java中的数据类型和C中的数据类型声明关键字有所不同,在java代码中需要使用Java类型来代替C类型,下表为Java类型和C类型对照表

参考文献

/lanxuezaipiao/p/3635556.html

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。