最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java本地方法(JNA)詳解及常見問題

 更新時間:2024年09月12日 10:06:57   作者:吳聲子夜歌  
JNA(Java?Native?Access)是一個開源Java框架,用于無需編寫JNI代碼即可動態(tài)訪問本地系統(tǒng)庫如Windows的dll,它允許Java程序直接調(diào)用本地方法,這篇文章主要介紹了Java本地方法(JNA)詳解及常見問題,需要的朋友可以參考下

JNA

1、概述

JNA 全稱 Java Native Access,是一個建立在經(jīng)典的 JNI 技術之上的 Java 開源框架。JNA 提供一組 Java 工具類用于在運行期動態(tài)訪問系統(tǒng)本地庫(native library:如 Window 的 dll)而不需要編寫任何 Native/JNI 代碼。開發(fā)人員只要在一個 java 接口中描述目標 native library 的函數(shù)與結(jié)構,JNA 將自動實現(xiàn) Java 接口到native function 的映射。

官方網(wǎng)站:https://github.com/java-native-access/jna

Maven依賴:

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

Java Native Access  

PackageDescription
com.sun.jnaProvides simplified native library access.

提供簡化的本機庫訪問權限。

com.sun.jna.ptrProvides various native pointer-to-type ( <type> *) representations.

提供各種母語指針到類型(<類型> *)表示。

com.sun.jna.win32Provides type and function mappers required for standard APIs on the Windows platform.

提供Windows平臺上標準API所需的類型和功能映射器。

Platform Utilities  

PackageDescription
com.sun.jna.platformProvides cross-platform utilities based on platform-specific libraries.

根據(jù)特定于平臺的庫提供跨平臺實用程序。

com.sun.jna.platform.dndProvides integrated, extended drag and drop functionality, allowing ghosted drag images to be used on all platforms.

提供集成的擴展拖放和丟棄功能,允許縮重拖動圖像在所有平臺上使用。

Platform Specific  

PackageDescription
com.sun.jna.platform.linuxProvides common library mappings for Linux.

為Linux提供公共圖書館映射。

com.sun.jna.platform.macProvides common library mappings for the OS X platform.

為OS X平臺提供公共庫映射。

com.sun.jna.platform.unixProvides common library mappings for Unix and X11-based platforms.

為基于UNIX和X11的平臺提供公共圖書館映射。

com.sun.jna.platform.unix.aixProvides common library mappings for the AIX platform.

為AIX平臺提供公共庫映射。

com.sun.jna.platform.unix.solarisProvides common library mappings for the Solaris (SunOS) platform.

為Solaris(Sunos)平臺提供公共圖書館映射。

com.sun.jna.platform.win32Provides common library mappings for the Windows platform.

為Windows平臺提供公共庫映射。

com.sun.jna.platform.win32.COMProvides common library mappings for Windows Component Object Model (COM).

為Windows組件對象模型(COM)提供公共庫映射。

com.sun.jna.platform.win32.COM.tlbProvides common library mappings for COM Type Libraries.

為COM類型庫提供公共庫映射。

com.sun.jna.platform.win32.COM.tlb.impProvides common library mappings for COM Type Library implementations.

為COM類型庫實現(xiàn)提供公共庫映射。

com.sun.jna.platform.win32.COM.utilProvides COM Utilities

提供Com Utilities.

com.sun.jna.platform.win32.COM.util.annotationProvides COM Utility annotations

提供com實用程序注釋

com.sun.jna.platform.winceProvides common library mappings for the Windows CE platform.

為Windows CE平臺提供公共庫映射。

Other Packages  

PackageDescription
com.sun.jna.internalProvides internal utilities.

提供內(nèi)部實用程序。

2、入門案例

2.1、示例一(調(diào)用系統(tǒng)共享庫)

獲取mac平臺下的C共享庫,然后調(diào)用printf函數(shù)打印。

public class HelloWorld {

    /**
     * 定義一個接口,默認的是繼承Library,如果動態(tài)鏈接庫里額函數(shù)是以stdcall方式輸出的,那么就繼承StdCallLibrary
     * 這個接口對應一個動態(tài)連接文件(windows:.dll, linux:.so, mac:.dylib)
     */
    public interface CLibrary extends Library {
        /**
         * 接口內(nèi)部需要一個公共靜態(tài)常量INSTANCE,通過這個常量就可以獲得這個接口的實例,從而使用接口的方法,也就是調(diào)用外部dll/so/dylib的函數(shù)
         * 該常量通過Native.load()這個API獲得
         * 第一個參數(shù)為共享庫的名稱(不帶后綴)
         * 第二個參數(shù)為本接口的Class類型,JNA通過這個這個Class類型,反射創(chuàng)建接口的實例
         * 共享庫的查找順序是:
         *  先從當前類的當前文件夾找,如果沒找到
         *  再從工程當前文件夾下面找,如果找不到
         *  最后在當前平臺下面去搜索
         */
        CLibrary INSTANCE = Native.load("c", CLibrary.class);

        /**
         * 接口中只需要定義要用到的函數(shù)或者公共變量,不需要的可以不定義
         * z注意參數(shù)和返回值的類型,應該和共享庫中的函數(shù)誒行保持一致
         */
        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]);
        }
    }
}

運行時指定參數(shù)為a b c d,運行結(jié)果如下:

Hello,World
Argument 0:a
Argument 1:b
Argument 2:c
Argument 3:d

2.2、示例二(調(diào)用自定義共享庫)

自定義一個求和C函數(shù)hello.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>

int add(int a, int b)
{
    return a + b;
}

編譯為共享庫hello.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o hello.dylib hello.c

使用JNA調(diào)用該共享庫中的add函數(shù):

public class HelloJNA {

    public interface LibraryAdd extends Library {
        //使用絕對路徑加載
        LibraryAdd LIBRARY_ADD = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/hello.dylib", LibraryAdd.class);

        int add(int a, int b);
    }

    public static void main(String[] args) {
        //調(diào)用映射的接口函數(shù)
        int add = LibraryAdd.LIBRARY_ADD.add(10, 15);
        System.out.println(add);
    }
}

輸出:

25

2、指針參數(shù)Pointer

在JAVA中都是值傳遞,但是因為使用JNA框架,目標函數(shù)是C/C++是有地址變量的,很多時候都需要將變量的結(jié)果帶回,因此,地址傳遞在JNA項目中幾乎是必須的。

2.1、使用場景

自定義求和C函數(shù),文件add.c:

//返回a+b的值
//同時c和msg通過指針參數(shù)返回
int add(int a, int b, int *c, char **msg)
{
    *c = (a + b) * 2;
    char *string = "hello world!";
    *msg = string;
    return a + b;
}

編譯為共享庫add.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o add.dylib add.c

使用JNA調(diào)用該共享庫中的add函數(shù):

public class AddTest {

    public interface LibAdd extends Library {
        LibAdd INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/add.dylib", LibAdd.class);

        int add(int a, int b, int c, String msg);
    }

    public static void main(String[] args) {
        int c = 0;
        String msg = "start";
        int add = LibAdd.INSTANCE.add(10, 15, c, msg);
        System.out.println("求和結(jié)果:" + add);
        System.out.println("c:" + c);
        System.out.println("msg:" + msg);
    }
}

結(jié)果顯而易見,無論add函數(shù)對c和msg做了何種改變,返回java中,值都不會變更。甚至會因為我們對c和msg賦值導致C函數(shù)訪問到奇怪的地址,導致報錯。

2.2、Pointer類

JNA框架提供了com.sun.jna.Pointer,指針數(shù)據(jù)類型,用于匹配轉(zhuǎn)換映射函數(shù)的指針變量。

創(chuàng)建Pointer:

//這樣的指針變量定義很像C的寫法,就是在定義的時候申請空間。
Pointer c = new Memory(50);
Pointer msg = new Memory(50);

Pointer映射指定的指針類型:

//映射C中的int*類型
//獲取int類型在內(nèi)存中需要的空間大小
int size = Native.getNativeSize(Integer.class); 
//為Pointer開辟int類型需要的內(nèi)存空間
Pointer int_pointer = new Memory(size);

//映射C中的double*類型
Pointer double_pointer = new Memory(Native.getNativeSize(Double.class));

Pointer設置/獲取值:

Pointer的setXxx方法提供了為各種類型設置值的方法:

第一個參數(shù)為偏移量,第二個參數(shù)為值。

//設置int
int_pointer.setInt(0, 123);
//設置double
double_pointer.setDouble(0, 22.33);

Pointer的getXxx方法提供了為各種類型獲取值的方法:

獲取單個值的參數(shù)為偏移量,獲取數(shù)組還需要傳遞一個獲取數(shù)量。

//獲取int
int anInt = int_pointer.getInt(0);
//獲取double
double aDouble = double_pointer.getDouble(0);

釋放Pointer:

Native.free(Pointer.nativeValue(c));     //手動釋放內(nèi)存
Pointer.nativeValue(c, 0);      		//避免Memory對象被GC時重復執(zhí)行Nativ.free()方法


Native.free(Pointer.nativeValue(msg));   
Pointer.nativeValue(msg, 0);      

2.3、案例

//返回a+b的值
//同時c和msg通過指針參數(shù)返回
int add(int a, int b, int *c, char **msg)
{
    *c = (a + b) * 2;
    char *string = "hello world!";
    *msg = string;
    return a + b;
}
public class AddTest {

    public interface LibAdd extends Library {
        LibAdd INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/add.dylib", LibAdd.class);

        int add(int a, int b, Pointer c, Pointer msg);
    }

    public static void main(String[] args) {
        //int類型指針
        Pointer c = new Memory(Native.getNativeSize(Integer.class));
        //二級指針,所以嵌套Pointer
        Pointer msg = new Memory(Native.getNativeSize(Pointer.class));

        int add = LibAdd.INSTANCE.add(10, 15, c, msg);
        System.out.println("求和結(jié)果:" + add);
        System.out.println("c:" + c.getInt(0));
        //msg實際是二級指針,所以要先獲取一級指針,再獲取值
        System.out.println("msg:" + msg.getPointer(0).getString(0));

        Native.free(Pointer.nativeValue(c));   //手動釋放內(nèi)存
        Pointer.nativeValue(c, 0);      //避免Memory對象被GC時重復執(zhí)行Native.free()方法

        Native.free(Pointer.nativeValue(msg));
        Pointer.nativeValue(msg, 0);
    }
}

輸出:

求和結(jié)果:25
c:50
msg:hello world!

3、引用對象ByReference

JNA框架提供了com.sun.jna.ptr.ByReference,引用對象類型,提供通用的“指向類型的指針”功能,通常在C代碼中用于向調(diào)用方返回值以及函數(shù)結(jié)果。

3.1、使用場景

在低版本的JNA中,如果C中函數(shù)執(zhí)行失敗時,沒有對指針進行處理,那么使用Pointer就會得到一個垃圾值。

C函數(shù)文件test.c:

int test_pointer(int a, int *b)
{
    if (a < 0)
    {
        //未對*b進行處理
        return -1;
    }
    *b = a;
    return 0;
}

編譯為共享庫test.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o test.dylib test.c

使用JNA調(diào)用該共享庫中的test_pointer函數(shù):

public class PointerTest {

    public interface LibPointerTest extends Library {
        LibPointerTest INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/test.dylib", LibPointerTest.class);

        int test_pointer(int a, Pointer b);
    }

    public static void main(String[] args) {
        int a = -10;
        Pointer b = new Memory(Native.getNativeSize(Integer.class));

        int add = LibPointerTest.INSTANCE.test_pointer(a, b);
        System.out.println(add);
        System.out.println(a);
        System.out.println(b.getInt(0));
    }
}

輸出:

-1
-10
0

本文使用的為5.10版,并未發(fā)現(xiàn)垃圾值的問題。

3.2、ByReference類

ByReference提供了很多繼承類,類似Pointer的指針屬性,每種數(shù)據(jù)類型都對應子類供使用比如int的用IntByReference,字符串的使用PointerByReference。

創(chuàng)建ByReference:

//無參構造,默認值為0
IntByReference intRef = new IntByReference();

//有參構造,根據(jù)指定值創(chuàng)建
IntByReference intRef = new IntByReference(4);

設置/獲取值:

//設置
intRef.setValue(10);
//獲取
intRef.getValue();

3.3、案例

int test_pointer(int a, int *b)
{
    if (a < 0)
    {
        //未對*b進行處理
        return -1;
    }
    *b = a;
    return 0;
}
public class PointerTest {

    public interface LibPointerTest extends Library {
        LibPointerTest INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/test.dylib", LibPointerTest.class);

        int test_pointer(int a, ByReference b);
    }

    public static void main(String[] args) {
        int a = 10;
        IntByReference b = new IntByReference();

        int add = LibPointerTest.INSTANCE.test_pointer(10, b);
        System.out.println(add);
        System.out.println(a);
        System.out.println(b.getValue());
    }
}

輸出:

0
10
10

3.4、Pointer與ByReference對比

  • Pointer和ByReference都可以在JNA項目中用來地址傳遞參數(shù)
  • Pointer使用方式類似C/C++需要手動分配/回收內(nèi)存
  • ByReference使用方式就是Java語法,內(nèi)存通過垃圾回收機制自動完成

總的來講ByReference更加方便,但是對于多層的指針引用,可能Pointer更合適處理嵌套結(jié)構。

4、Java模擬C結(jié)構體

4.1、使用場景

結(jié)構體作為參數(shù)有兩個點,一個是傳入,一個是返回。傳入的還分傳值和傳引用。

目標C程序,struct.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// teacher 結(jié)構體定義
typedef struct {
    int tea_age;
    char *tea_name;
} Teacher;

// student 結(jié)構體定義
typedef struct {
    int stu_age;
    char *stu_name;
} Student;



Teacher stuTea(Student stu, Teacher *tea) {

    printf("stu-name=%s/n", stu.stu_name);
    printf("stu-age=%d/n", stu.stu_age);

    // 將stu復制給tea做函數(shù)返回
    Teacher teacher;
    teacher.tea_name = stu.stu_name;
    teacher.tea_age = stu.stu_age;

    tea->tea_name = strcat(tea->tea_name, "是好老師");

    return teacher;
}

函數(shù)內(nèi)部的功能也簡單:

  • 打印stu的內(nèi)容【驗證值傳遞是否正確】
  • 把stu的內(nèi)容復制給結(jié)果變量teacher,用于函數(shù)返回【驗證是否能返回結(jié)構體】
  • 改變傳入結(jié)構體變量tea的值【驗證結(jié)構體引用傳遞是否生效】

編譯為共享庫struct.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct.dylib struct.c

JNA調(diào)用:

public class StructTest {

    //定義一個接口,描述本地庫
    public interface LibStruct extends Library {
        LibStruct INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct.dylib", LibStruct.class);

        //定義結(jié)構體
        class TeacherStruct extends Structure {
            //結(jié)構體參數(shù)類型及順序要嚴格按照C結(jié)構體的類型及順序
            public int tea_age;
            public String tea_name;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends TeacherStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends TeacherStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            //重寫getFieldOrder獲取字段列表, 很重要,沒有會報錯
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"tea_age", "tea_name"});
            }

            @Override
            public String toString() {
                return "TeacherStruct{" +
                        "tea_age=" + tea_age +
                        ", tea_name='" + tea_name + '\'' +
                        "} " + super.toString();
            }
        }

        //定義結(jié)構體
        class StudentStruct extends Structure {
            public int stu_age;
            public String stu_name;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends StudentStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends StudentStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            //重寫getFieldOrder獲取字段列表, 很重要,沒有會報錯
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"stu_age", "stu_name"});
            }

            @Override
            public String toString() {
                return "StudentStruct{" +
                        "stu_age=" + stu_age +
                        ", stu_name='" + stu_name + '\'' +
                        "} " + super.toString();
            }
        }

        //描述本地函數(shù)
        TeacherStruct.ByValue stuTea(StudentStruct.ByValue stu, TeacherStruct.ByReference tea);
    }

    public static void main(String[] args) {
        LibStruct.StudentStruct.ByValue stuByValue = new LibStruct.StudentStruct.ByValue();
        LibStruct.TeacherStruct.ByReference teaByReference = new LibStruct.TeacherStruct.ByReference();

        stuByValue.stu_age = 18;
        stuByValue.stu_name = "小學生";

        teaByReference.tea_age = 48;
        teaByReference.tea_name = "高級教師";

        // 調(diào)用函數(shù)之前
        System.out.println("調(diào)用函數(shù)之前teaByReference:" + teaByReference.toString());

        // 調(diào)用方法。返回結(jié)果
        LibStruct.TeacherStruct.ByValue result = LibStruct.INSTANCE.stuTea(stuByValue, teaByReference);

        // 查看傳地址的teaByReference的值是否變更
        System.out.println("調(diào)用函數(shù)之后teaByReference:" + teaByReference.toString());

        // 函數(shù)返回結(jié)果
        System.out.println("調(diào)用函數(shù)返回結(jié)果result.name:" + result.toString());

    }
}

輸出:

調(diào)用函數(shù)之前teaByReference:TeacherStruct{tea_age=48, tea_name='高級教師'} StructTest$LibStruct$TeacherStruct$ByReference(auto-allocated@0x7ffc36203c40 (16 bytes)) {
  int tea_age@0x0=0x0030
  String tea_name@0x8=高級教師
}
調(diào)用函數(shù)之后teaByReference:TeacherStruct{tea_age=48, tea_name='高級教師是好老師'} StructTest$LibStruct$TeacherStruct$ByReference(auto-allocated@0x7ffc36203c40 (16 bytes)) {
  int tea_age@0x0=0x0030
  String tea_name@0x8=高級教師是好老師
}
調(diào)用函數(shù)返回結(jié)果result.name:TeacherStruct{tea_age=18, tea_name='小學生'} StructTest$LibStruct$TeacherStruct$ByValue(auto-allocated@0x7ffc3620b480 (16 bytes)) {
  int tea_age@0x0=0x0012
  String tea_name@0x8=小學生
}
stu-name=小學生/nstu-age=18/n

4.2、Structure類

要使用 Java 類模擬 C 的結(jié)構體,需要 Java 類繼承Structure類。

必須要注意,Structure子類中的公共字段的順序,必須與 C 語言中的結(jié)構的順序保持一致,否則會報錯!因為,Java 調(diào)用動態(tài)鏈接庫中的 C 函數(shù),實際上就是一段內(nèi)存作為函數(shù)的參數(shù)傳遞給 C 函數(shù)。動態(tài)鏈接庫以為這個參數(shù)就是 C 語言傳過來的參數(shù)。同時,C 語言的結(jié)構體是一個嚴格的規(guī)范,它定義了內(nèi)存的次序。因此,JNA 中模擬的結(jié)構體的變量順序絕對不能錯。

如果一個 Struct 有 2 個 int 變量 int a, int b,如果 JNA 中的次序和 C 語言中的次序相反,那么不會報錯,但是數(shù)據(jù)將會被傳遞到錯誤的字段中去。

另外,Structure類有兩個內(nèi)部接口Structure.ByReferenceStructure.ByValue。

這兩個接口僅僅是標記:

  • 如果一個類實現(xiàn) Structure.ByReference 接口,就表示這個類代表結(jié)構體指針。
  • 如果一個類實現(xiàn) Structure.ByValue 接口,就表示這個類代表結(jié)構體本身。
  • 如果不實現(xiàn)這兩個接口,那么就相當于你實現(xiàn)了 Structure.ByReference 接口。

使用這兩個接口的實現(xiàn)類,可以明確定義我們的 Structure 實例表示的是結(jié)構體指針還是結(jié)構體本身。

4.3、結(jié)構體本身作為參數(shù)

struct_self_param.c

#include <stdio.h>

struct User {
    long id;
    char* name;
    int age;
};

void sayUser(struct User user)
{
    printf("id:%ld\n", user.id);
    printf("name:%s\n", user.name);
    printf("age:%d\n", user.age);
}

編譯為共享庫struct_self_param.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct_self_param.dylib struct_self_param.c

JNA調(diào)用:

public class StructSelfParamTest {

    //描述本地共享庫
    public interface LibStructSelfParam extends Library {
        LibStructSelfParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_self_param.dylib", LibStructSelfParam.class);

        //定義結(jié)構體
        class UserStruct extends Structure {
            //公共字段的順序,必須與C語言中的結(jié)構的順序保持一致
            public NativeLong id;
            public String name;
            public int age;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends UserStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends UserStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            // 重寫getFieldOrder獲取字段列表, 很重要,沒有會報錯
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"id", "name", "age"});
            }
        }
        
        //描述本地函數(shù),值傳遞
        void sayUser(UserStruct.ByValue user);
    }
    
    public static void main(String[] args) {
        LibStructSelfParam.UserStruct.ByValue user = new LibStructSelfParam.UserStruct.ByValue();
        user.id = new NativeLong(10000);
        user.name = "tom";
        user.age = 18;
        LibStructSelfParam.INSTANCE.sayUser(user);
    }
}

輸出:

id:10000
name:tom
age:18

4.3、結(jié)構體指針作為參數(shù)

struct_pointer_param.c

#include <stdio.h>

struct User {
    long id;
    char* name;
    int age;
};

void sayUser(struct User* user)
{
    printf("use strcture pointer\n");
    printf("id:%ld\n", user->id);
    printf("name:%s\n", user->name);
    printf("age:%d\n", user->age);
}

編譯為共享庫struct_pointer_param.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct_pointer_param.dylib struct_pointer_param.c

JNA調(diào)用:

public class StructPointerParamTest {
    //描述本地共享庫
    public interface LibStructPointerParam extends Library {
        LibStructPointerParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_pointer_param.dylib", LibStructPointerParam.class);

        //定義結(jié)構體
        class UserStruct extends Structure {
            //公共字段的順序,必須與C語言中的結(jié)構的順序保持一致
            public NativeLong id;
            public String name;
            public int age;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends StructSelfParamTest.LibStructSelfParam.UserStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends StructSelfParamTest.LibStructSelfParam.UserStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            // 重寫getFieldOrder獲取字段列表, 很重要,沒有會報錯
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"id", "name", "age"});
            }
        }

        //描述本地函數(shù),指針傳遞
        void sayUser(UserStruct.ByReference user);
    }

    public static void main(String[] args) {
        LibStructPointerParam.UserStruct.ByReference user = new LibStructPointerParam.UserStruct.ByReference();
        user.id = new NativeLong(10000);
        user.name = "tom";
        user.age = 18;
        LibStructPointerParam.INSTANCE.sayUser(user);
    }
}

輸出:

use strcture pointer
id:10000
name:tom
age:18

4.4、嵌套結(jié)構體本身作為參數(shù)

C 語言最復雜的數(shù)據(jù)類型就是結(jié)構體。結(jié)構體的內(nèi)部可以嵌套結(jié)構體,這使它可以模擬任何類型的對象。JNA 也可以模擬這類復雜的結(jié)構體,結(jié)構體內(nèi)部可以包含結(jié)構體對象指針的數(shù)組。

struct_nested_param.c

#include <stdio.h>

struct User {
    long id;
    char* name;
    int age;
};

struct Company {
    long id;
    const char* name;
    struct User users[3];
    int count;
};


void showNestedStruct(struct Company company)
{
    printf("This is nested struct.\n");
    printf("company id is:%ld\n", company.id);
    printf("company name is:%s\n", company.name);
    for (int i =0; i < 3; i++)
    {
        printf("user[%d] info of company\n", i);
        printf("user id:%ld\n", company.users[i].id);
        printf("user name:%s\n", company.users[i].name);
        printf("user age:%d\n", company.users[i].age);
    }
    printf("count %d\n", company.count);
}

編譯為共享庫struct_nested_param.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct_nested_param.dylib struct_nested_param.c

JNA調(diào)用:

public class StructNestedParamTest {

    //描述本地共享庫
    public interface LibStructNestedParam extends Library {
        LibStructNestedParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_nested_param.dylib", LibStructNestedParam.class);

        //定義User結(jié)構體
        class UserStruct extends Structure {
            //公共字段的順序,必須與C語言中的結(jié)構的順序保持一致
            public NativeLong id;
            public String name;
            public int age;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends UserStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends UserStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            // 重寫getFieldOrder獲取字段列表, 很重要,沒有會報錯
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"id", "name", "age"});
            }
        }

        //定義Company結(jié)構體
        class CompanyStruct extends Structure {
            //公共字段的順序,必須與C語言中的結(jié)構的順序保持一致
            public NativeLong id;
            public String name;
            public UserStruct.ByValue[] users = new UserStruct.ByValue[3];
            public int count;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends CompanyStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends CompanyStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            // 重寫getFieldOrder獲取字段列表, 很重要,沒有會報錯
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"id", "name", "users", "count"});
            }

        }

        //描述本地函數(shù),值傳遞
        void showNestedStruct(CompanyStruct.ByValue company);
    }

    public static void main(String[] args) {
        LibStructNestedParam.UserStruct.ByValue user1 = new LibStructNestedParam.UserStruct.ByValue();
        user1.id = new NativeLong(1);
        user1.name = "zhangsan";
        user1.age = 18;

        LibStructNestedParam.UserStruct.ByValue user2 = new LibStructNestedParam.UserStruct.ByValue();
        user2.id = new NativeLong(2);
        user2.name = "lisi";
        user2.age = 19;

        LibStructNestedParam.UserStruct.ByValue user3 = new LibStructNestedParam.UserStruct.ByValue();
        user3.id = new NativeLong(3);
        user3.name = "wangwu";
        user3.age = 20;

        LibStructNestedParam.CompanyStruct.ByValue company = new LibStructNestedParam.CompanyStruct.ByValue();
        company.id = new NativeLong(1000001);
        company.name = "XXXXXX有限責任公司";
        company.count = 3;
        company.users[0] = user1;
        company.users[1] = user2;
        company.users[2] = user3;

        LibStructNestedParam.INSTANCE.showNestedStruct(company);
    }
}

輸出:

This is nested struct.
company id is:1000001
company name is:XXXXXX有限責任公司
user[0] info of company
user id:1
user name:zhangsan
user age:18
user[1] info of company
user id:2
user name:lisi
user age:19
user[2] info of company
user id:3
user name:wangwu
user age:20
count 3

4.5、嵌套結(jié)構體指針作為參數(shù)

struct_nested_pointer_param.c

#include <stdio.h>

struct User {
    long id;
    char* name;
    int age;
};

struct Company {
    long id;
    const char* name;
    struct User users[3];
    int count;
};


void showNestedStruct(struct Company* company)
{
    printf("This is nested struct.\n");
    printf("company id is:%ld\n", company->id);
    printf("company name is:%s\n", company->name);
    for (int i =0; i < 3; i++)
    {
        printf("user[%d] info of company\n", i);
        printf("user id:%ld\n", company->users[i].id);
        printf("user name:%s\n", company->users[i].name);
        printf("user age:%d\n", company->users[i].age);
    }
    printf("count %d\n", company->count);
}

編譯為共享庫struct_nested_pointer_param.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct_nested_pointer_param.dylib struct_nested_pointer_param.c

JNA調(diào)用:

public class StructNestedPointerParamTest {
    //描述本地共享庫
    public interface LibStructNestedPointerParam extends Library {
        LibStructNestedPointerParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_nested_pointer_param.dylib", LibStructNestedPointerParam.class);

        //定義User結(jié)構體
        class UserStruct extends Structure {
            //公共字段的順序,必須與C語言中的結(jié)構的順序保持一致
            public NativeLong id;
            public String name;
            public int age;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends UserStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends UserStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            // 重寫getFieldOrder獲取字段列表, 很重要,沒有會報錯
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"id", "name", "age"});
            }
        }

        //定義Company結(jié)構體
        class CompanyStruct extends Structure {
            //公共字段的順序,必須與C語言中的結(jié)構的順序保持一致
            public NativeLong id;
            public String name;
            public UserStruct.ByValue[] users = new UserStruct.ByValue[3];
            public int count;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends CompanyStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends CompanyStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            // 重寫getFieldOrder獲取字段列表, 很重要,沒有會報錯
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"id", "name", "users", "count"});
            }

        }

        //描述本地函數(shù),指針傳遞
        void showNestedStruct(CompanyStruct.ByReference company);
    }

    public static void main(String[] args) {
        LibStructNestedPointerParam.UserStruct.ByValue user1 = new LibStructNestedPointerParam.UserStruct.ByValue();
        user1.id = new NativeLong(1);
        user1.name = "zhangsan";
        user1.age = 18;

        LibStructNestedPointerParam.UserStruct.ByValue user2 = new LibStructNestedPointerParam.UserStruct.ByValue();
        user2.id = new NativeLong(2);
        user2.name = "lisi";
        user2.age = 19;

        LibStructNestedPointerParam.UserStruct.ByValue user3 = new LibStructNestedPointerParam.UserStruct.ByValue();
        user3.id = new NativeLong(3);
        user3.name = "wangwu";
        user3.age = 20;

        LibStructNestedPointerParam.CompanyStruct.ByReference company = new LibStructNestedPointerParam.CompanyStruct.ByReference();
        company.id = new NativeLong(1000001);
        company.name = "XXXXXX有限責任公司";
        company.count = 3;
        company.users[0] = user1;
        company.users[1] = user2;
        company.users[2] = user3;

        LibStructNestedPointerParam.INSTANCE.showNestedStruct(company);
    }
}

輸出:

This is nested struct.
company id is:1000001
company name is:XXXXXX有限責任公司
user[0] info of company
user id:1
user name:zhangsan
user age:18
user[1] info of company
user id:2
user name:lisi
user age:19
user[2] info of company
user id:3
user name:wangwu
user age:20
count 3

4.6、結(jié)構體中嵌套結(jié)構體數(shù)組

1)、作為輸入?yún)?shù)

struct_nested_array_param.c

#include <stdio.h>

typedef struct {
    int enable;
    int x;
    int y;
    int width;
    int height;
} area_pos;

typedef struct {
    int enable;
    int x;
    int y;
} spot_pos;

typedef struct {
    int enable;
    int sta_x;
    int sta_y;
    int end_x;
    int end_y;
} line_pos;

typedef struct {
    area_pos area[2];
    spot_pos spot[2];
    line_pos line;
} image_pos;

void get_struct_array_value(image_pos *img_data){
    printf("line_pos enable:%d\n",img_data->line.enable);
    printf("line_pos sta_x:%d\n",img_data->line.sta_x);
    printf("line_pos sta_y:%d\n",img_data->line.sta_y);
    printf("line_pos end_x:%d\n",img_data->line.end_x);
    printf("line_pos end_y:%d\n",img_data->line.end_y);
    for (int i = 0; i<2;i++){
        printf("area_pos[%d] enable:%d\n",i,img_data->area[i].enable);
        printf("area_pos[%d] x:%d\n",i,img_data->area[i].x);
        printf("area_pos[%d] y:%d\n",i,img_data->area[i].y);
        printf("area_pos[%d] width:%d\n",i,img_data->area[i].width);
        printf("area_pos[%d] height:%d\n",i,img_data->area[i].height);
    }
    for (int j = 0; j < 2; j++){
        printf("spot_pos[%d] enable:%d\n",j,img_data->spot[j].enable);
        printf("spot_pos[%d] x:%d\n",j,img_data->spot[j].x);
        printf("spot_pos[%d] y:%d\n",j,img_data->spot[j].y);
    }
}

編譯為共享庫struct_nested_array_param.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct_nested_array_param.dylib struct_nested_array_param.c

JNA調(diào)用:

public class StructNestedArrayParamTest {

    public interface LibStructNestedArrayParam extends Library {
        LibStructNestedArrayParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_nested_array_param.dylib", LibStructNestedArrayParam.class);

        class AreaPos extends Structure {
            public int enable;
            public int x;
            public int y;
            public int width;
            public int height;

            public static class ByReference extends AreaPos implements Structure.ByReference { }
            public static class ByValue extends AreaPos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"enable", "x", "y", "width", "height"});
            }
        }

        class SpotPos extends Structure {
            public int enable;
            public int x;
            public int y;

            public static class ByReference extends SpotPos implements Structure.ByReference { }
            public static class ByValue extends SpotPos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"enable", "x", "y"});
            }
        }

        class LinePos extends Structure {
            public int enable;
            public int sta_x;
            public int sta_y;
            public int end_x;
            public int end_y;

            public static class ByReference extends LinePos implements Structure.ByReference { }
            public static class ByValue extends LinePos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"enable", "sta_x", "sta_y", "end_x", "end_y"});
            }
        }

        class ImagePos extends Structure {
            public AreaPos.ByValue[] area = new AreaPos.ByValue[2];
            public SpotPos.ByValue[] spot = new SpotPos.ByValue[2];
            public LinePos.ByValue line;

            public static class ByReference extends ImagePos implements Structure.ByReference { }
            public static class ByValue extends ImagePos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"area", "spot", "line"});
            }
        }

        void get_struct_array_value(ImagePos.ByReference img);
    }

    public static void main(String[] args) {
        LibStructNestedArrayParam.AreaPos.ByValue a1 = new LibStructNestedArrayParam.AreaPos.ByValue();
        a1.enable = 1;
        a1.x = 10;
        a1.y = 20;
        a1.height = 1080;
        a1.width = 1920;

        LibStructNestedArrayParam.AreaPos.ByValue a2 = new LibStructNestedArrayParam.AreaPos.ByValue();
        a1.enable = 0;
        a1.x = 20;
        a1.y = 10;
        a1.height = 1920;
        a1.width = 1080;

        LibStructNestedArrayParam.SpotPos.ByValue s1 = new LibStructNestedArrayParam.SpotPos.ByValue();
        s1.enable = 0;
        s1.x = 1;
        s1.y = 1;

        LibStructNestedArrayParam.SpotPos.ByValue s2 = new LibStructNestedArrayParam.SpotPos.ByValue();
        s1.enable = 1;
        s1.x = 2;
        s1.y = 2;

        LibStructNestedArrayParam.LinePos.ByValue line = new LibStructNestedArrayParam.LinePos.ByValue();
        line.enable = 0;
        line.end_x = 10;
        line.end_y = 20;
        line.sta_x = 30;
        line.sta_y = 40;

        LibStructNestedArrayParam.ImagePos.ByReference img = new LibStructNestedArrayParam.ImagePos.ByReference();
        img.area[0] = a1;
        img.area[1] = a2;
        img.spot[0] = s1;
        img.spot[1] = s2;
        img.line = line;

        LibStructNestedArrayParam.INSTANCE.get_struct_array_value(img);
    }
}

輸出:

line_pos enable:0
line_pos sta_x:30
line_pos sta_y:40
line_pos end_x:10
line_pos end_y:20
area_pos[0] enable:0
area_pos[0] x:20
area_pos[0] y:10
area_pos[0] width:1080
area_pos[0] height:1920
area_pos[1] enable:0
area_pos[1] x:0
area_pos[1] y:0
area_pos[1] width:0
area_pos[1] height:0
spot_pos[0] enable:1
spot_pos[0] x:2
spot_pos[0] y:2
spot_pos[1] enable:0
spot_pos[1] x:0
spot_pos[1] y:0

2)、作為輸出參數(shù)

結(jié)構體中嵌套結(jié)構體數(shù)組用作輸出參數(shù)時,需要對結(jié)構體數(shù)組的第一個元素賦初值。

struct_nested_array_out.c

#include <stdio.h>

typedef struct {
    int enable;
    int x;
    int y;
    int width;
    int height;
} area_pos;

typedef struct {
    int enable;
    int x;
    int y;
} spot_pos;

typedef struct {
    int enable;
    int sta_x;
    int sta_y;
    int end_x;
    int end_y;
} line_pos;

typedef struct {
    area_pos area[2];
    spot_pos spot[2];
    line_pos line;
} image_pos;

void set_struct_array_value(image_pos *img_data){
    area_pos a1,a2;
    a1.enable = 1;
    a1.x = 10;
    a1.y = 20;
    a1.height = 1090;
    a1.width = 1920;
    a2.enable = 0;
    a2.x = 20;
    a2.y = 10;
    a2.height = 1920;
    a2.width = 1080;
    
    spot_pos s1,s2;
    s1.enable = 0;
    s1.x = 1;
    s1.y = 1;
    s2.enable = 1;
    s2.x = 2;
    s2.y = 2;
    
    line_pos l;
    l.enable = 0;
    l.end_x = 10;
    l.end_y = 20;
    l.sta_x = 30;
    l.sta_y = 40; 

	img_data->area[0] = a1;
    img_data->area[1] = a2;
    img_data->spot[0] = s1;
    img_data->spot[1] = s2;
    img_data->line = l;
}

編譯為共享庫struct_nested_array_out.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct_nested_array_out.dylib struct_nested_array_out.c

JNA調(diào)用:

public class StructNestedArrayOutTest {

    public interface LibStructNestedArrayOut extends Library {
        LibStructNestedArrayOut INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_nested_array_out.dylib", LibStructNestedArrayOut.class);

        class AreaPos extends Structure {
            public int enable;
            public int x;
            public int y;
            public int width;
            public int height;

            public static class ByReference extends AreaPos implements Structure.ByReference { }
            public static class ByValue extends AreaPos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"enable", "x", "y", "width", "height"});
            }

            @Override
            public String toString() {
                return "AreaPos{" +
                        "enable=" + enable +
                        ", x=" + x +
                        ", y=" + y +
                        ", width=" + width +
                        ", height=" + height +
                        "} " + super.toString();
            }
        }

        class SpotPos extends Structure {
            public int enable;
            public int x;
            public int y;

            public static class ByReference extends SpotPos implements Structure.ByReference { }
            public static class ByValue extends SpotPos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"enable", "x", "y"});
            }

            @Override
            public String toString() {
                return "SpotPos{" +
                        "enable=" + enable +
                        ", x=" + x +
                        ", y=" + y +
                        "} " + super.toString();
            }
        }

        class LinePos extends Structure {
            public int enable;
            public int sta_x;
            public int sta_y;
            public int end_x;
            public int end_y;

            public static class ByReference extends LinePos implements Structure.ByReference { }
            public static class ByValue extends LinePos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"enable", "sta_x", "sta_y", "end_x", "end_y"});
            }

            @Override
            public String toString() {
                return "LinePos{" +
                        "enable=" + enable +
                        ", sta_x=" + sta_x +
                        ", sta_y=" + sta_y +
                        ", end_x=" + end_x +
                        ", end_y=" + end_y +
                        "} " + super.toString();
            }
        }

        class ImagePos extends Structure {
            public AreaPos.ByValue[] area = new AreaPos.ByValue[2];
            public SpotPos.ByValue[] spot = new SpotPos.ByValue[2];
            public LinePos.ByValue line;

            public static class ByReference extends ImagePos implements Structure.ByReference { }
            public static class ByValue extends ImagePos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"area", "spot", "line"});
            }
        }

        void set_struct_array_value(ImagePos.ByReference img);
    }

    public static void main(String[] args) {
        LibStructNestedArrayOut.ImagePos.ByReference img = new LibStructNestedArrayOut.ImagePos.ByReference();
        // img.area[0] = new LibStructNestedArrayOut.AreaPos.ByValue();
        // img.spot[0] = new LibStructNestedArrayOut.SpotPos.ByValue();
        LibStructNestedArrayOut.INSTANCE.set_struct_array_value(img);
        for (int i = 0; i < 2; i++)
            System.out.println(img.area[i]);
        for (int i = 0; i < 2; i++)
            System.out.println(img.spot[i]);
        System.out.println(img.line);
    }
}

如果未對數(shù)組第一項賦值,會報java.lang.IndexOutOfBoundsException

Exception in thread "main" java.lang.IndexOutOfBoundsException: Bounds exceeds available space : size=20, offset=40

所以一定要對輸出參數(shù)中的數(shù)組第一項賦值:

public static void main(String[] args) {
    LibStructNestedArrayOut.ImagePos.ByReference img = new LibStructNestedArrayOut.ImagePos.ByReference();
    img.area[0] = new LibStructNestedArrayOut.AreaPos.ByValue();
    img.spot[0] = new LibStructNestedArrayOut.SpotPos.ByValue();
    LibStructNestedArrayOut.INSTANCE.set_struct_array_value(img);
    for (int i = 0; i < 2; i++)
        System.out.println(img.area[i]);
    for (int i = 0; i < 2; i++)
        System.out.println(img.spot[i]);
    System.out.println(img.line);
}

輸出:

AreaPos{enable=1, x=10, y=20, width=1920, height=1090} StructNestedArrayOutTest$LibStructNestedArrayOut$AreaPos$ByValue(allocated@0x7fb3b0d1bd10 (20 bytes) (shared from auto-allocated@0x7fb3b0d1bd10 (84 bytes))) {
  int enable@0x0=0x0001
  int x@0x4=0x000A
  int y@0x8=0x0014
  int width@0xC=0x0780
  int height@0x10=0x0442
}
AreaPos{enable=0, x=20, y=10, width=1080, height=1920} StructNestedArrayOutTest$LibStructNestedArrayOut$AreaPos$ByValue(allocated@0x7fb3b0d1bd24 (20 bytes) (shared from auto-allocated@0x7fb3b0d1bd10 (84 bytes))) {
  int enable@0x0=0x0000
  int x@0x4=0x0014
  int y@0x8=0x000A
  int width@0xC=0x0438
  int height@0x10=0x0780
}
SpotPos{enable=0, x=1, y=1} StructNestedArrayOutTest$LibStructNestedArrayOut$SpotPos$ByValue(allocated@0x7fb3b0d1bd38 (12 bytes) (shared from auto-allocated@0x7fb3b0d1bd10 (84 bytes))) {
  int enable@0x0=0x0000
  int x@0x4=0x0001
  int y@0x8=0x0001
}
SpotPos{enable=1, x=2, y=2} StructNestedArrayOutTest$LibStructNestedArrayOut$SpotPos$ByValue(allocated@0x7fb3b0d1bd44 (12 bytes) (shared from auto-allocated@0x7fb3b0d1bd10 (84 bytes))) {
  int enable@0x0=0x0001
  int x@0x4=0x0002
  int y@0x8=0x0002
}
LinePos{enable=0, sta_x=30, sta_y=40, end_x=10, end_y=20} StructNestedArrayOutTest$LibStructNestedArrayOut$LinePos$ByValue(allocated@0x7fb3b0d1bd50 (20 bytes) (shared from auto-allocated@0x7fb3b0d1bd10 (84 bytes))) {
  int enable@0x0=0x0000
  int sta_x@0x4=0x001E
  int sta_y@0x8=0x0028
  int end_x@0xC=0x000A
  int end_y@0x10=0x0014
}

4.7、結(jié)構體數(shù)組作為參數(shù)

文件struct_array_param.c

#include <stdio.h>
#include <string.h>

typedef struct {
    int age;
    char name[20];
} Person;


int changeObjs(Person per[], int size)
{
    if (size <= 0) 
    {
        return -1;
    }
    for (int i = 0; i < size; i++)
    {
        per[i].age *= 10;
        strcpy(per[i].name, "wokettas");
    }
    for (int k = 0; k < size; k++)
    {
        printf("person[%d] age:%d\n", k, per[k].age);
        printf("person[%d] name:%s\n", k, per[k].name);
    }
    return 0;
}

編譯為共享庫struct_array_param.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct_array_param.dylib struct_array_param.c

1)、錯誤的調(diào)用一

public class StructArrayParamTest {

    public interface LibStructArrayParam extends Library {
        LibStructArrayParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_array_param.dylib", LibStructArrayParam.class);

        class Person extends Structure {
            public int age;
            public byte[] name = new byte[20];

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"age", "name"});
            }

            //值傳遞
            public static class ByValue extends Person implements Structure.ByValue { }

        }

        //描述函數(shù)
        int changeObjs(Person.ByValue[] per, int size);
    }

    public static void main(String[] args) {
        LibStructArrayParam.Person.ByValue[] per = new LibStructArrayParam.Person.ByValue[2];
        LibStructArrayParam.Person.ByValue p1 = new LibStructArrayParam.Person.ByValue();
        LibStructArrayParam.Person.ByValue p2 = new LibStructArrayParam.Person.ByValue();
        p1.age = 1;
        p1.name = Arrays.copyOf("tom".getBytes(), 20);
        p2.age = 2;
        p2.name = Arrays.copyOf("jerry".getBytes(), 20);
        per[0] = p1;
        per[1] = p2;

        LibStructArrayParam.INSTANCE.changeObjs(per, 2);
    }
}

如果在 Java 接口聲明中錯誤把參數(shù)類型寫成Person.ByValue,會報java.lang.IndexOutOfBoundsException。將參數(shù)類型改為結(jié)構體本身即可,即不帶 ByReference 或 ByValue。結(jié)構體數(shù)組做參數(shù)時, 要區(qū)別于非數(shù)組的 ByReference 和 ByValue。

2)、錯誤的調(diào)用二

public class StructArrayParamTest {

    public interface LibStructArrayParam extends Library {
        LibStructArrayParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_array_param.dylib", LibStructArrayParam.class);

        class Person extends Structure {
            public int age;
            public byte[] name = new byte[20];

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"age", "name"});
            }
        }

        //描述函數(shù)
        int changeObjs(Person[] per, int size);
    }

    public static void main(String[] args) {
        LibStructArrayParam.Person[] per = new LibStructArrayParam.Person[2];
        LibStructArrayParam.Person p1 = new LibStructArrayParam.Person();
        LibStructArrayParam.Person p2 = new LibStructArrayParam.Person();
        p1.age = 1;
        p1.name = Arrays.copyOf("tom".getBytes(), 20);
        p2.age = 2;
        p2.name = Arrays.copyOf("jerry".getBytes(), 20);
        per[0] = p1;
        per[1] = p2;

        LibStructArrayParam.INSTANCE.changeObjs(per, 2);
    }
}

會報錯Exception in thread "main" java.lang.IllegalArgumentException: Structure array elements must use contiguous memory (bad backing address at Structure array index 1)

結(jié)構體數(shù)組必須使用連續(xù)的內(nèi)存區(qū)域。p1,p2 都是 new 出來的對象,不可能連續(xù),用傳統(tǒng)方式初始化數(shù)組不能解決。

應使用JNA提供的toArray方法:

public Structure[] toArray(int size);

3)、正確的調(diào)用

public class StructArrayParamTest {

    public interface LibStructArrayParam extends Library {
        LibStructArrayParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_array_param.dylib", LibStructArrayParam.class);

        class Person extends Structure {
            public int age;
            public byte[] name = new byte[20];

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"age", "name"});
            }
        }

        //描述函數(shù)
        int changeObjs(Person[] per, int size);
    }

    public static void main(String[] args) {
        LibStructArrayParam.Person per = new LibStructArrayParam.Person();
        LibStructArrayParam.Person[] pers = (LibStructArrayParam.Person[]) per.toArray(2);
        pers[0].age = 1;
        pers[0].name = Arrays.copyOf("tom".getBytes(), 20);
        pers[1].age = 2;
        pers[1].name = Arrays.copyOf("jerry".getBytes(), 20);

        LibStructArrayParam.INSTANCE.changeObjs(pers, 2);
    }
}

輸出:

person[0] age:10
person[0] name:wokettas
person[1] age:20
person[1] name:wokettas

5、常見問題

5.1、Java 類的字段聲明必須與重寫方法保持一致

類中變量名要和重寫后的方法中的保持一致(名稱不一致,變量個數(shù)不一致都會失敗),否則編譯不通過。

Java 中模擬結(jié)構體時,類名可以和 C 的結(jié)構體名稱不同,只需要 Java 類的各個字段名稱、 各字段順序?qū)Y(jié)構體中的字段即可。

5.2、Java映射C數(shù)組亂碼問題

文件array_param.c

#include <stdio.h>
#include <string.h>

typedef struct {
    int enable;
    char static_ip[20];
    char netmask[20];
    char gateway[20];
    char dns1[20];
    char dns2[20];
}network_eth;

int sdk_set_network_eth(const char *ip, network_eth *network_param)
{
    if (strlen(ip) == 0 || network_param == NULL)
    { 
        printf("sdk_set_network_eth param error!\n"); 
        return -1;
    }
    printf("ip:%s\n",ip);
    printf("network_eth enable:%d\n",network_param->enable); 
    printf("network_eth static_ip:%s\n",network_param->static_ip); 
    printf("network_eth netmask:%s\n",network_param->netmask); 
    printf("network_eth gateway:%s\n",network_param->gateway); 
    printf("network_eth dns1:%s\n",network_param->dns1); 
    printf("network_eth dns2:%s\n",network_param->dns2);
    return 0;
}

編譯為共享庫array_param.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o array_param.dylib array_param.c

JNA調(diào)用:

public class CharArrayTest {

    public interface LibCharArray extends Library {
        LibCharArray INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/array_param.dylib", LibCharArray.class);


        class NetWorkEth extends Structure {
            public int enable;
            public byte[] static_ip = new byte[20];
            public byte[] netmask = new byte[20];
            public byte[] gateway = new byte[20];
            public byte[] dns1 = new byte[20];
            public byte[] dns2 = new byte[20];

            public static class ByReference extends NetWorkEth implements Structure.ByReference{}
            public static class ByValue extends NetWorkEth implements Structure.ByValue{}

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[] {"enable","static_ip","netmask","gateway","dns1","dns2"});
            }
        }

        int sdk_set_network_eth(byte[] ip, NetWorkEth.ByReference netWork);
    }

    public static void main(String[] args) {
        String ip = "127.0.0.1";
        LibCharArray.NetWorkEth.ByReference netWorkEth = new LibCharArray.NetWorkEth.ByReference();
        netWorkEth.enable = 1;
        netWorkEth.static_ip = "10.20.6.10".getBytes();
        netWorkEth.netmask = "255.255.255.0".getBytes();
        netWorkEth.gateway = "192.168.122.134".getBytes();
        netWorkEth.dns1 = "114.114.114.114".getBytes();
        netWorkEth.dns2 = "8.8.8.8".getBytes();

        int res = LibCharArray.INSTANCE.sdk_set_network_eth(ip.getBytes(), netWorkEth);
        System.out.println(res);

    }

輸出:

0
ip:127.0.0.1
network_eth enable:1
network_eth static_ip:10.20.6.10255.255.255.0192.168.122.134114.114.114.1148.8.8.8127.0.0.1
network_eth netmask:5.0192.168.122.134114.114.114.1148.8.8.8127.0.0.1
network_eth gateway:4.114.114.1148.8.8.8127.0.0.1
network_eth dns1:127.0.0.1
network_eth dns2:??#mRealVarArgsCheckerlang/O

輸出亂碼!因為C/C++的數(shù)組類型在內(nèi)存中是連續(xù)存儲的,而Java的數(shù)組不一定是連續(xù)的。對C中的char數(shù)組類型賦值時,不能直接給數(shù)組賦值,要使用Arrays.copyOf(String.getBytes(), 20)賦值,數(shù)組長度和C結(jié)構體中聲明的長度保持一致。

在某些情況下,雖然使用 String.getBytes()轉(zhuǎn)換也能成功,但大多數(shù)情況下,使用該方法會出 現(xiàn)亂碼,不建議使用 String.getBytes()。

public static void main(String[] args) {
    String ip = "127.0.0.1";
    byte[] ipArr = Arrays.copyOf(ip.getBytes(), 20);
    LibCharArray.NetWorkEth.ByReference netWorkEth = new LibCharArray.NetWorkEth.ByReference();
    netWorkEth.enable = 1;
    netWorkEth.static_ip = Arrays.copyOf("10.20.6.10".getBytes(), 20);
    netWorkEth.netmask = Arrays.copyOf("255.255.255.0".getBytes(), 20);
    netWorkEth.gateway = Arrays.copyOf("192.168.122.134".getBytes(), 20);
    netWorkEth.dns1 = Arrays.copyOf("114.114.114.114".getBytes(), 20);
    netWorkEth.dns2 = Arrays.copyOf("8.8.8.8".getBytes(), 20);

    int res = LibCharArray.INSTANCE.sdk_set_network_eth(ipArr, netWorkEth);
    System.out.println(res);
}

輸出:

0
ip:127.0.0.1
network_eth enable:1
network_eth static_ip:10.20.6.10
network_eth netmask:255.255.255.0
network_eth gateway:192.168.122.134
network_eth dns1:114.114.114.114
network_eth dns2:8.8.8.8

創(chuàng)建結(jié)構體數(shù)組應該使用 JNA 的 toArray()方法,而不是 Java 常規(guī)創(chuàng)建數(shù)組的方法,因為內(nèi) 存空間在 java 中是不連續(xù)的,jna 定義數(shù)組是需要使用 toArray 方法,這樣實例化出來的數(shù) 組內(nèi)存空間是連續(xù)的。

5.3、Java 接收 C 函數(shù)返回類型為 char*

JNA 使用 String 無法直接接收 C 函數(shù)返回類型為 char*的值,必須要用 Pointer 進行接收。

當 C 函數(shù)的參數(shù)為 char*、const char*用做輸入時,JNA 可以使用 String 類型進行傳 參,此時可以正常調(diào)用 C 函數(shù);但當C函數(shù)的參數(shù)類型為char*且用作輸出時,使用 String 類型無法正常接收,必須使用 Pointer 進行處理。

文件char_out.c

#include <stdio.h>
#include <string.h>

void append_str(char* str, char* append)
{
    printf("str:%s\n", str);
    printf("append:%s\n", append);
    int length = strlen(str);
    char* p = str;
    for(int i = 0; i < length; i++)
    {
        p++;
    }
    strcpy(p, append);
}

編譯為共享庫char_out.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o char_out.dylib char_out.c

JNA調(diào)用,使用Pointer接收char*返回值:

public class CharOutTest {

    public interface LibCharOut extends Library {
        LibCharOut INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/char_out.dylib", LibCharOut.class);

        void append_str(Pointer str, String append);
    }

    public static void main(String[] args) {
        Pointer str = new Memory(40);
        str.setString(0, "hello");
        String append = " world";
        LibCharOut.INSTANCE.append_str(str, append);
        System.out.println(str.getString(0));
    }
}

輸出:

hello world
str:hello
append: world

通過 Java 獲取 char * 字符串,必須要通過 Java 傳入一個 com.sun.jna.Pointer 指針變量,然后在 DLL 中將值賦給此指針變量,然后通過此指針變量獲取值。

5.4、動態(tài)庫和 jdk 的位數(shù)必須匹配

64 位的 jdk 只能調(diào)用 64 位的 dll,32 位也一樣。如果使用的 jdk 和 dll 位數(shù)不同,會報 Unable to load DLL 'xxx.dll': 找不到指定的模塊或者java.lang.UnsatisfiedLinkError: %1 不是有效的 Win32 應用程序。

5.5、動態(tài)庫版本必須和系統(tǒng)類型匹配

  • windows:后綴名為.dll
  • linux:后綴名為.so
  • mac:后綴名為.dylib

總結(jié) 

到此這篇關于Java本地方法(JNA)詳解及常見問題的文章就介紹到這了,更多相關Java本地方法JNA內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SpringBoot整合Redis、ApachSolr和SpringSession的示例

    SpringBoot整合Redis、ApachSolr和SpringSession的示例

    本篇文章主要介紹了SpringBoot整合Redis、ApachSolr和SpringSession的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • servlet實現(xiàn)文件下載的步驟及說明詳解

    servlet實現(xiàn)文件下載的步驟及說明詳解

    這篇文章主要為大家詳細介紹了servlet實現(xiàn)文件下載的步驟及說明,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • flink?RichFunction之坑及解決

    flink?RichFunction之坑及解決

    這篇文章主要介紹了flink?RichFunction之坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • Java類的加載時機與過程

    Java類的加載時機與過程

    這篇文章主要介紹了Java類的加載時機與過程,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2021-12-12
  • Java必備知識之位運算及常見進制解讀

    Java必備知識之位運算及常見進制解讀

    從現(xiàn)代計算機中所有的數(shù)據(jù)二進制的形式存儲在設備中。即 0、1 兩種狀態(tài),計算機對二進制數(shù)據(jù)進行的運算(+、-、*、/)都是叫位運算,即將符號位共同參與運算的運算
    2021-10-10
  • Kafka攔截器的神奇操作方法

    Kafka攔截器的神奇操作方法

    Kafka攔截器是一種強大的機制,用于在消息發(fā)送和接收過程中插入自定義邏輯,它們可以用于消息定制、日志記錄、監(jiān)控、業(yè)務邏輯集成、性能統(tǒng)計和異常處理等,本文介紹Kafka攔截器的神奇操作,感興趣的朋友一起看看吧
    2025-01-01
  • SpringBoot自定義轉(zhuǎn)換器用法詳解

    SpringBoot自定義轉(zhuǎn)換器用法詳解

    在SpringBoot中,轉(zhuǎn)換器用于將一個類型的值轉(zhuǎn)換為另一個類型,這在處理HTTP請求參數(shù)、響應結(jié)果、表單數(shù)據(jù)等方面非常有用,SpringBoot提供了多種方式來定義和使用轉(zhuǎn)換器,本文給大家介紹了
    如何使用SpringBoot自定義轉(zhuǎn)換器,需要的朋友可以參考下
    2023-08-08
  • 深入理解Netty?FastThreadLocal優(yōu)缺點及實現(xiàn)邏輯

    深入理解Netty?FastThreadLocal優(yōu)缺點及實現(xiàn)邏輯

    本文以線上詭異問題為切入點,通過對比JDK ThreadLocal和Netty FastThreadLocal實現(xiàn)邏輯以及優(yōu)缺點,并深入解讀源碼,由淺入深理解Netty FastThreadLocal
    2023-10-10
  • Java 添加文本框到PPT幻燈片過程解析

    Java 添加文本框到PPT幻燈片過程解析

    這篇文章主要介紹了Java 添加文本框到PPT幻燈片過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-09-09
  • Java實現(xiàn)PDF文件的分割與加密功能

    Java實現(xiàn)PDF文件的分割與加密功能

    這篇文章主要為大家分享了如何利用Java語言實現(xiàn)PDF文件的分割與加密以及封面圖的生成,文中的示例代碼簡潔易懂,感興趣的可以了解一下
    2022-04-04

最新評論

高陵县| 凤城市| 雷州市| 天峨县| 木兰县| 秀山| 克山县| 洪泽县| 广德县| 濮阳县| 赤壁市| 金门县| 张家界市| 花垣县| 江西省| 额尔古纳市| 东辽县| 外汇| 丁青县| 阿拉尔市| 广安市| 南汇区| 德令哈市| 沾益县| 蕉岭县| 曲阳县| 红安县| 东丽区| 武义县| 茂名市| 思茅市| 宁海县| 伊宁县| 平定县| 奉化市| 正阳县| 错那县| 五台县| 龙井市| 宜君县| 拜城县|