天天看點

JNA 實際開發中若幹問題解決方法

摘要: JNA 實際開發中若幹問題解決方法

JNA 實際開發中若幹問題解決方法

很早就已經聽說過 JNI(Java Native Interface)Java 本地接口,奈何調用本地動态連結庫太過于複雜,就一直沒有再嘗試。而最近因為工作需要調用 Windows DLL 動态連結庫(對應 Linux 中 so 檔案),而對 JNA 有了入坑體驗,對實際工作中遇到的問題做出總結。

調用 Windows 視窗列印Hello World

pom 依賴

<dependency>

<groupId>net.java.dev.jna</groupId>

<artifactId>jna</artifactId>

<version>latest</version>

</dependency>

JNA 在加載驅動時提供兩種加載方式 , 直接映射 和 接口生成。

接口生成

public interface HelixcsDll extends StdCallLibrary {

// loadLibary 為動态連結庫加載目錄

HelixcsDll HELIXCS_DLL = Native.loadLibrary("helixcs.dll", HelixcsDll.class);

// 在 dll 中存在相同 SomeFunction 的函數

void SomeFunction(String content);

}

直接映射

class Helixcs{

static {

Native.register("helixcs.dll");

// 映射為本地方法

public static native void SomeFunction(String content);

C 類型和 Java 類型映射。

JNA 官方提供的預設類型映射

Default Type Mappings 預設類型映射

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

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

char 8-bit integer byte BYTE, TCHAR

short 16-bit integer short WORD

wchar_t 16/32-bit character char TCHAR

int 32-bit integer int DWORD

int boolean value boolean BOOL

long 32/64-bit integer NativeLong LONG

long long 64-bit integer long __int64

float 32-bit FP float

double 64-bit FP double

char C string String LPTCSTR

void pointer Pointer LPVOID, HANDLE, LPXXX

未簽名類型作為簽名類型來映射。 C 中枚舉類型可替換為 “int”。

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

官方提供的詳細的類型映射

Marshalling/Unmarshalling (Java/Native Type Conversions)

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 NativeMapped and NativeLong are converted to Pointer before being passed to the native layer.

long platform-dependent (32- or 64-bit integer) NativeLong

const char NUL-terminated array (native encoding or jna.encoding) 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 Structure Union

struct[] array of structs, contiguous in memory Structure[]

void (FP)() function pointer (Java or native) Callback

pointer (<T> ) same as Pointer PointerType

other integer type IntegerType

other custom mapping, depends on definition NativeMapped

經驗總結預設映射關系

盡管 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位

常見錯誤

UnsatisfiedLinkError 問題

存在多個動态連結庫之間調用情況,可能缺少其中某一個動态連結庫檔案。

Error Memory Access 問題

較大情況下存在參數類型映射錯誤,參考 JNA 類型映射。

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

程式在運作一段時間後崩潰

在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

參考

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

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

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

下一篇: Vue3 起步

繼續閱讀