目录

JNA (Java 本地访问)概述

C 语言 与 Java

JNA 入门示例

msvcrt.dll 运行库

printf 打印方法

kernel32 动态链接库

GetLogicalDriveStringsA

GetSystemDirectoryA


本文参考网址:https://blog.csdn.net/gwd1154978352/article/details/55097376

本文基于 win10 的 64 位操作系统

JNA (Java 本地访问)概述

1、JNA 全称 Java Native Access (Java 本地访问),JNA 提供一组 Java 工具类用于在运行期间动态访问系统本地库(native library:如Window的dll)而不需要编写任何Native/JNI代码。

2、开发人员只要在一个Java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射。

3、JNA全称Java Native Access,是一个建立在经典的JNI(Java Native Interface-Java本地接口)技术之上的Java开源框架

4、Github托管地址:https://github.com/java-native-access/jna

5、JNA 开发包下载地址

  1. https://maven.java.net/content/repositories/releases/net/java/dev/jna/jna/4.0.0/jna-4.0.0.jar

  2. https://maven.java.net/content/repositories/releases/net/java/dev/jna/jna-platform/4.0.0/jna-platform-4.0.0.jar

6、官方入门示例:https://github.com/java-native-access/jna/blob/master/www/GettingStarted.md

6、通俗的说就是使用 JNA 可以更方便的调用 windows/Linux 系统底层的函数(方法)

C 语言 与 Java

1、Windows 底层主要使用 C++ 编写以及还有 C 语言加汇编语言,Linux 主要以 C 语言为主

2、dll 和 so 是 C 函数的集合和容器,这与 Java 中的接口概念吻合,所以 JNA 把 dll 文件和 so 文件看成一个个接口。在 JNA 中定义一个接口就是相当于了定义一个 DLL/SO 文件的描述文件,该接口代表了动态链接库中发布的所有函数。而且,对于程序不需要的函数,可以不在接口中声明。

3、JNA 定义的接口一般继承 com.sun.jna.Library 接口,如果dll文件中的函数是以stdcall方式输出函数,那么该接口就应该继承com.sun.jna.win32.StdCallLibrary接口。

4、JNA 难点在于学 Java 的人完全不知道电脑系统底层到底有哪些库?库叫什么名字?库中有哪些函数?函数是什么含义?等等

Java 和 C 数据类型对照表

Java 类型

C 类型

原生表现

 

boolean

int

32位整数(可定制)

 

byte

char

8位整数

 

char

wchar_t

平台依赖

 

short

short

16位整数

 

int

int

32位整数

 

long

long long, __int64

64位整数

 

float

float

32位浮点数

 

double

double

64位浮点数

 

Buffer/Pointer

pointer

平台依赖(32或64位指针)

 

<T>[] (基本类型的数组)

pointer/array

32或64位指针(参数/返回值)

邻接内存(结构体成员)

 

String

char*

/0结束的数组 (native encoding or jna.encoding)

 

WString

wchar_t*

/0结束的数组(unicode)

 

String[]

char**

/0结束的数组的数组

 

WString[]

wchar_t**

/0结束的宽字符数组的数组

 

Structure

struct*/struct

指向结构体的指针(参数或返回值) (或者明确指定是结构体指针)结构体(结构体的成员) (或者明确指定是结构体)

 

Union

union

等同于结构体

 

Structure[]

struct[]

结构体的数组,邻接内存

 

Callback

<T> (*fp)()

Java函数指针或原生函数指针

 

NativeMapped

varies

依赖于定义

 

NativeLong

long

平台依赖(32或64位整数)

 

PointerType

pointer

和Pointer相同

JNA 入门示例

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]);}}
}

1、运行程序,没带参数时只打印出“Hello, World”,带了参数时,则会打印出所有的参数。

2、没有写一行 C 代码,就直接在 Java 中调用了系统动态链接库中的函数!

程序说明:

一:自定义接口

public interface CLibrary extends Library {  .....

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

二:接口内部定义

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

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

INSTANCE 常量通过 Native.loadLibrary() API函数获得,该函数有2个参数:

第一个参数是动态链接库dll/so的名称,但不带.dll或.so这样的后缀,这符合JNI的规范,因为带了后缀名就不可以跨操作系统平台了。搜索动态链接库路径的顺序是:先从当前类的当前文件夹找,如果没有找到,再在工程当前文件夹下面找win32/win64文件夹,找到后搜索对应的dll文件,如果找不到再到WINDOWS下面去搜索,再找不到就会抛异常了。比如上例中printf函数在Windows平台下所在的dll库名称是"msvcrt",而在其它平台如Linux下的so库名称是"c"。

第二个参数是自定义接口的Class类型。JNA通过这个Class类型,根据指定的.dll/.so文件,动态创建接口的实例。该实例由JNA通过反射自动生成。

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

三:调用链接库函数

定义好接口后,就可以使用接口中的方法即相应dll/so中的函数了,通过接口中的实例即可进行调用

如:CLibrary.INSTANCE.printf("Hello, World\n");  即可调用系统中的printf函数

msvcrt.dll 运行库

1、msvcrt.dll 是微软在windows操作系统中提供的C语言运行库执行文件(Microsoft Visual C Runtime Library)

2、msvcrt.dll 中提供了printf,malloc,strcpy 等 C语言库函数的具体运行实现

printf 打印方法

1、第一步自定义接口继承Library,接口名称建议与库名称一致,如 Msvcrt。如果dll库文件中的函数是以stdcall方式输出,那么自定义接口就应该继承com.sun.jna.win32.StdCallLibrary接口。

2、使用 Native 加载链接库,msvcrt的后缀名.dll不要写,想要使用msvcrt.dll库中哪些方法,就在自定义接口声明它即可

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
/*** Created by Administrator on 2018/6/27 0027.*/
public interface Msvcrt extends Library {Msvcrt INSTANCE = (Msvcrt) Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),Msvcrt.class);void printf(String format, Object... args);
}

3、第二步则是常见自定义接口的实例调用接口中的方法,也是msvcrt库中的函数

/*** 测试msvcrt.dll的printf方法*/
@Test
public void test1() {Msvcrt msvcrt = Msvcrt.INSTANCE;msvcrt.printf("Hello JNA");
}

kernel32 动态链接库

1、kernel32.dll 是Windows中非常重要的32位动态链接库文件,属于内核级文件。

2、kernel32.dll 控制着系统的内存管理、数据的输入输出操作和中断处理,当Windows启动时,kernel32.dll就驻留在内存中特定的写保护区域,使别的程序无法占用这个内存区域。

3、kernel32.dll库中有GetLogicalDriveStringsA、GetSystemDirectoryA等方法

GetLogicalDriveStringsA

1、获取本地系统的系统盘符

2、自定义接口,然后指明动态链接库名称,同时声明方法

import com.sun.jna.Library;
import com.sun.jna.Native;
/*** Created by Administrator on 2018/6/27 0027.*/
public interface Kernel32 extends Library {Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);/*** 【获取本地系统逻辑盘符】* @param length* @param buffer* @return*/int GetLogicalDriveStringsA(int length,byte[] buffer);
}
/*** 测试kernel32.dll的GetLogicalDriveStringsA方法* 【获取本地系统逻辑盘符】*/
@Test
public void test2() {Kernel32 kernel32 = Kernel32.INSTANCE;byte[] buffer2 = new byte[64];/*** GetLogicalDriveStringsA方法会把结果缓存到buffer2字节数组中* logicalDriveStringsSize:方法返回值其实是结果的大小*/int logicalDriveStringsSize = kernel32.GetLogicalDriveStringsA(buffer2.length / 2, buffer2);StringBuilder stringBuilder = new StringBuilder(logicalDriveStringsSize);for (byte bt : buffer2) {stringBuilder.append((char) bt);}String logicalDriveStrings = stringBuilder.toString().trim();System.out.println(logicalDriveStrings);
}

GetSystemDirectoryA

import com.sun.jna.Library;
import com.sun.jna.Native;
/*** Created by Administrator on 2018/6/27 0027.*/
public interface Kernel32 extends Library {Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);/*** 【获取本地系统逻辑盘符】* @param length* @param buffer* @return*/int GetLogicalDriveStringsA(int length,byte[] buffer);/*** 【获取系统目录】* @param buffer* @param size* @return*/int GetSystemDirectoryA(byte[] buffer,int size);
}
/*** 测试kernel32.dll的GetSystemDirectoryA方法* 【获取系统目录】*/
@Test
public void test3() {Kernel32 kernel32 = Kernel32.INSTANCE;byte[] buffer = new byte[50];/*** 同理此方法也是将结果缓存到了字节数组中,数组大小自己设置即可* 返回值systemDirectoryStrSize仍然是结果的长度大小*/int systemDirectoryStrSize = kernel32.GetSystemDirectoryA(buffer, 50);StringBuilder stringBuilder = new StringBuilder(systemDirectoryStrSize);for (byte bt : buffer) {stringBuilder.append((char) bt);}String systemDirectoryStr = stringBuilder.toString().trim();System.out.println(systemDirectoryStr);
}

JNA (Java 本地访问)理论概述与入门相关推荐

  1. java本地监听zk服务器节点【动态上下线】

    [README] java本地访问 zk cluster, refer 2 https://blog.csdn.net/PacosonSWJTU/article/details/111404364 [ ...

  2. 视频编码零基础入门(1):视频编解码之理论概述

    1.前言 即时通讯应用中的实时音视频技术,几乎是IM开发中的最后一道高墙.原因在于:实时音视频技术 = 音视频处理技术 + 网络传输技术 的横向技术应用集合体,而公共互联网不是为了实时通信设计的.有关 ...

  3. Java-Day11 面向对象遍程的入门 (类属性的默认值、构造方法、类的成员、static关键字、类的成员加载顺序、Java(权限)访问修饰符)

    目录 1. 类的属性的默认值问题 2. 构造方法(Constructor) 3. 类的成员 3.1 类的成员之一:属性 3.2 UML类图 4. static关键字 5. 类的成员加载(运行)顺序 6 ...

  4. java私塾 设计模式 视频_[章节]Java Web开发理论部分视频教程 之 04 mvc设计模式详解视频教程 - 我的学习中心 - 私塾在线 - 只做精品视频课程服务...

    第01节课:进行整体课程概览:复习事件机制:复习表现层的功能:复习表现层的开发 第02节课:Web应用的基础知识,包括:Internet.Http.IP.Port.MIME规范.Web客户端和服务端. ...

  5. 视频编解码之理论概述 和即时通信

    前言 即时通讯应用中的实时音视频技术,几乎是IM开发中的最后一道高墙.原因在于:实时音视频技术 = 音视频处理技术 + 网络传输技术 的横向技术应用集合体,而公共互联网不是为了实时通信设计的.有关实时 ...

  6. 学习笔记:Java 并发编程①_基础知识入门

    若文章内容或图片失效,请留言反馈. 部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 视频链接:https://www.bilibili.com/video/av81461839 视频下载: ...

  7. Linux负载均衡解决方案 -- LVS 理论概述

    Lvs 理论概述 一.什么是 LVS ? 二.为什么需要 LVS ? 三.LVS 原理 1.LVS 体系结构 2.LVS 工作模式 3.LVS 调度算法 四.LVS 工作方式 1.LVS-DR 模式 ...

  8. Apache Thrift 官网学习 一 基本概述与入门

    文章目录 一 基本概述与入门 1.1 官网知识 1.2 下载安装 1.3 基本数据结构 1.4 基本案例入门 1.4.1 编写thrift文件 1.4.2 新建springBoot项目 1.4.3 生 ...

  9. Java本地高性能缓存的几种实现方式

    Java缓存技术可分为远端缓存和本地缓存,远端缓存常用的方案有著名的redis和memcache,而本地缓存的代表技术主要有HashMap,Guava Cache,Caffeine和Encahche. ...

  10. stylus vue 报错_【Vue】Re01 理论概念和入门上手

    一.Vue概述 什么是渐进式?1.把Vue作应用的一部分嵌套项目中2.如果完全抛弃其他组件和框架,Vue又具有丰富的生态和库莱支持3.Core + Router + VueX 满足项目绝大多数的需求- ...

最新文章

  1. 【 iOS 应用开发 】 UIKit 控件 ( 代码生成控件 | UIView 属性方法 | Storyboard | Bundle | Property List | 动画 | 图片内存优化 )
  2. MyBatis -- 结果集映射
  3. libevent简介和使用【转】
  4. 组态王接入多比物联网云平台
  5. Ubuntu常用APT命令参数
  6. python打印文件中的前三行_linux利用grep查看打印匹配的下几行或前后几行的命令...
  7. 用SwipeBackLayout让activity具有滑动返回的效果
  8. mysql备份文件0kb_Oracle 数据文件大小为0kb或者文件丢失恢复
  9. 一图看懂云栖大会「云原生」发布
  10. Windows Phone 7 定义和使用字典资源(ResourceDictionary)
  11. D3.js学习(二)
  12. ADNI数据库数据集下载权限申请
  13. 计算机 取得高级权限,win10获取system权限,win7获取最高权限
  14. 如何修改wamp5的端口号,默认页。
  15. 特斯拉神器TeslaMate一键安装,终于来了
  16. unity python热更新_Unity热更新介绍和测试方法
  17. 2021-07-23 N卡显示器亮度设置
  18. 单休和双休有多大区别(月薪1万和8千如何选择)
  19. mysql master_log_file_change master 未指定master_log_file
  20. matlab负无穷大到正无穷大怎么打,matlab中怎么定义n从负无穷到正无?

热门文章

  1. hdoj 1071 The Area 求面积
  2. 为什么败者树的访问外存次数要比胜者树少_为什么说蒙地卡罗搜索树MCTS是AlphaZero的核心?[AlphaZero理论篇之三]...
  3. mac安装helm工具_适用于初学者的基本 kubectl 和 Helm 命令
  4. 拓端tecdat|R语言弹性网络Elastic Net正则化惩罚回归模型交叉验证可视化
  5. 拓端tecdat|R语言马尔可夫区制转移模型Markov regime switching
  6. 拓端tecdat|python对NOAA天气数据格式转换
  7. 拓端tecdat|数据告诉你:互联网哪个职位最有前途?
  8. java 字符串转换int_java IPV4字符串转int或long
  9. 3-8 堆栈模拟队列 (25 分)
  10. spring cloud学习笔记01