1. 描述備注
1.1 JNA工作原理
JNA是建立在JNI技術基礎之上的一個Java類庫,它使您可以方便地使用java直接訪問動態鏈接庫中的函數。
原來使用JNI,你必須手工用C寫一個動態鏈接庫,在C語言中映射Java的數據類型。
JNA中,它提供了一個動態的C語言編寫的轉發器,可以自動實現Java和C的數據類型映射。你不再需要編寫C動態鏈接庫。
JNA把一個dll/.so文件看做是一個java接口。Dll是C函數的集合、容器,這和java接口的概念吻合。
Java Type |
C Type |
Native Representation |
boolean |
int |
32-bit integer (customizable) |
byte |
char |
8-bit integer |
char |
wchar_t |
platform-dependent |
short |
short |
16 bit integer |
int |
int |
32 bit integer |
long |
long long,_int64 |
64 bit integer |
float |
float |
32-bit floating point |
double |
double |
364-bit floating point |
Buffer Pointer |
pointer |
platform-dependent (32- or 64-bit pointer to memory) |
[] (array of primitive type)
|
32- or 64-bit pointer to memory (argument/return) contiguous memory (struct member) |
|
String |
char* |
NUL-terminated array (native encoding or jna.encoding) |
WString |
wchar* |
NUL-terminated array (unicode) |
String[] |
char** |
NULL-terminated array of C strings |
WString[] |
wchar** |
NULL-terminated array of wide C strings |
Structure |
struct* struct |
pointer to struct (argument or return) (or explicitly) struct by value (member of struct) (or explicitly) |
Union |
union |
same as Structure |
Structure[] |
struct[] |
array of structs, contiguous in memory |
Callback |
(*fp)()
|
function pointer (Java or native) |
NativeMapped |
varies |
depends on definition |
NativeLong |
long |
platform-dependent (32- or 64-bit integer) |
PointerType |
pointer |
same as Pointer |
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.5.0</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>4.5.0</version>
</dependency>
2. 示例
2.1示例1-普通調用
public class HelloWorld {
//定義一個接口,繼承自Library或stdCallLibrary,默認的是繼承Library ,如果動態鏈接庫里的函數是以stdcall方式輸出的,那么就繼承StdCallLibrary,比如眾所周知的kernel32庫。
public interface CLibrary extends Library {
//接口內部需要一個公共靜態常量:INSTANCE,通過這個常量,就可以獲得這個接口的實例,從而使用接口的方法,也就是調用外部dll/so的函數。
//通過Native.loadLibrary() API獲取,
//第一個參數是動態鏈接庫dll/so的名稱,不帶后綴。搜索動態鏈接庫路徑的順序是:當前類的目錄-->工程文件夾下面找win32/win64文件夾下搜
-->WINDOWS下面去搜索,再找不到就會拋異常了。比如上例中printf函數在Windows平台下所在的dll庫名稱是msvcrt,而在其它平台如Linux下的so庫名稱是c。
//第二個參數是本接口的Class類型。JNA通過這個Class類型,根據指定的.dll/.so文件,動態創建接口的實例。該實例由JNA通過反射自動生成
CLibrary INSTANCE = (CLibrary)Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),CLibrary.class);
//接口中只需要定義你要用到的函數或者公共變量,不需要的可以不定義,如上例只定義printf函數, 入參和出參和dll中定義保持一致
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]);
}
}
}
2.2 示例2-調用win32DLL(JNA已封裝)
//獲取系統時間
Kernel32 lib = Kernel32.INSTANCE;
SYSTEMTIME time = new SYSTEMTIME();
lib.GetSystemTime(time);
System.out.println("Today's integer value is " + time.wDay);
示例3-Win32API 操作進程
Kernel32 lib = Kernel32.INSTANCE;
// 獲取進程快照
HANDLE hSnapshot = lib.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPPROCESS, new DWORD(0));
// 獲取進程
PROCESSENTRY32 pe32 = new PROCESSENTRY32();
// lib.Process32First(hSnapshot, lppe);
while (lib.Process32Next(hSnapshot, pe32)) {
DWORD processId = pe32.th32ProcessID;
char[] name = pe32.szExeFile;
System.out.println("進程id: " + processId + " ; " + "進程名稱: " + new String(name));
// 打開進程
HANDLE processHandle = lib.OpenProcess(WinNT.PROCESS_ALL_ACCESS, false, pe32.th32ProcessID.intValue());
}