JNA调用库文件

Posted tangquanbin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JNA调用库文件相关的知识,希望对你有一定的参考价值。

最近项目中要集成厂商的卡口摄像头,需要通过jna调用库函数接收卡口相机抓拍的过车数据。本文记录了Java调用C语言动态库(jna)的调用方式、回调函数、结构体等。
JNA全称Java Native Access,是一个建立在经典的JNI技术之上的Java开源框架,主要解决jni调用其他语言繁琐的步骤。JNI是Java Native Interface的缩写,它提供了若干的api实现了Java和其他语言的通信(主要是c&c++).
jna 官方github:https://github.com/java-native-access/jna

下面来看看GettingStarted:
/**
 * GettingStarted
 * @author tangquanbin
 * @date 2018/8/28 15:39
 */
public class HelloWorld {

    /**
     * 需要定义一个接口,继承自Library 或StdCallLibrary
     * 默认的是继承Library ,如果动态链接库里的函数是以stdcall方式输出的,那么就继承StdCallLibrary
     */
    public interface CLibrary extends Library {
        /**
         * 实例化接口,从而使用接口的方法,也就是调用外部dll/so的函数。
         *
         * 第一个参数是动态链接库dll/so的名称,但不带.dll或.so这样的后缀,这符合JNI的规范,因为带了后缀名就不可以跨操作系统平台了。
         * 搜索动态链 接库路径的顺序是:先从当前类的当前文件夹找,如果没有找到,再在工程当前文件夹下面找win32/win64文件夹,
         * 找到后搜索对应的dll文件,如果 找不到再到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);

        /**
         * 参数和返回值的类型,应该和链接库中的函数类型保持一致。
         * @param format
         * @param args
         */
        void printf(String format, Object... args);
    }

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

jna调用的方式上面代码中的注释已经写得很清楚了,现在我们就来看看jna的函数调用、回调函数。

我们先来看看一般回调函数java的实现,其中加入了异步的思想,这也正是回调方法Callback最大的优势:

现在有一个场景,学生A、B是同学,学生A有到题不会做就ask学生B。

 1.会做题的接口

/**
 * 回调方法的优势
 * 回调方法最大的优势在于,异步回调
 * @author tangquanbin
 * @date 2018/8/30 15:54
 */
public interface Slover {
    void slove();
}

2.学生B  

/**
 * @author tangquanbin
 * @date 2018/8/30 15:58
 */
public class StudentB implements Slover{

    @Override
    public void slove() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("问题解决了");
    }

}

  

 3.学生A

/**
 * @author tangquanbin
 * @date 2018/8/30 15:57
 */
public class StudentA{
    public void ask(Slover slover) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                slover.slove();
            }
        }).start();
        goSomeThing();
    }
public void goSomeThing(){ System.out.println("StudentB,我去做其他事了"); } }

测试

 

/**
 * @author tangquanbin
 * @date 2018/09/02 22:34
 */
public class Test {
    public static void main(String[] args) {
        StudentA studentA = new StudentA();
        studentA.ask(new StudentB());
    }
}

 输出:  

        StudentB,我去做其他事了

         问题解决了

 

在JNA中回调方法要继承Callback或者StdCallCallback

下面这部分参考自:https://blog.csdn.net/ggmove/article/details/17377117

列如dll接口函数及回调函数类型:

typedef void (*Callback_Status)(char *station_id, char *station_ip, int status);
int Start_Server(char *ip, int port, Callback_Status fun);

java代码->回调函数声明:

public class getSDK {
	public interface Callback_Status extends StdCallCallback {
		public void Status(String station_id, String station_ip, int status);
	}
}

java代码->回调函数实现:

public class getSDK {
	public static class Status_Realize implements Callback_Status{
		public void Status(String station_id, String station_ip, int status) {
			if (status == 2) {
				GUI.Station_online(station_id, station_ip, 1, 0);
			} else if (status == 3) {
				GUI.Station_online(station_id, station_ip, 2, 0);
			}
		}
	}
}

 jna调用还有一个重要的知识点:结构体Structure。时间不早了等下次再补充吧。

 




以上是关于JNA调用库文件的主要内容,如果未能解决你的问题,请参考以下文章

找不到使用 JNA 调用的 DLL 所需的文件

在Linux环境下使用gfortran编译器生成fortran语言的.so共享对象文件 并使用JNA调用 带参方法

在Linux环境下使用gfortran编译器生成fortran语言的.so共享对象文件 并使用JNA调用 带参方法

在Linux环境下使用gfortran编译器生成fortran语言的.so共享对象文件 并使用JNA调用 带参方法

Linux下JNA 调用 so 库

Java调用明华RF读写器DLL文件的方法