`

JNA调用C实现的DLL

 
阅读更多

(此处以C写的DLL为例子)

第一部分:简单了解DLL里的函数
1
、创建一个动态链接库项目testJNA
2
、在头文件里声明函数

IRIS_SDK_API int STDCALL ik_release_enroll_device (IK_ENROLL_DEVICE_HANDLE dev_handle);
3
、在源码里实现函数

int STDCALL ik_release_enroll_device (IK_ENROLL_DEVICE_HANDLE dev_handle) {

       printf(“。。。。”);

       return 1;

}
4
、生成dll文件:testJNA.dll

5、将要调用的函数所在dll以及这些dll所依赖的dll都拷贝到windows/system32下(一定要将所有依赖的dll都找到,可以到网上下载个工具

 

第二部分:JNA调用DLL的函数

JNA使用一个java接口来代表一个动态链接库发布的所有函数。
对于不需要的原生函数,可以不在java接口中声明java方法原型。

5、定义一个表示链接库的接口如果dll是以stdcall方式输出函数,那么就继承StdCallLibrary。否则就继承默认的Library接口。此接口里定义一个实例 

TestJnaLib INSTANCE = (TestJnaLib)Native.loadLibrary((Platform.isWindows() ? "testJNA.dll" : "c"), TestJnaLib.class);//标蓝的地方一定要这么写

此实例由jna通过反射自动生成。

 

此接口支持在Java端多线程、并发调用本地方法。如果本地类库不是线程安全的,可用

TestJnaLib INSTANCE2 =  Native.synchronizedLibrary(INSTANCE);

来阻止多线程同时访问本地代码。


6
、在表示链接库的接口里定义对应dll里的方法

 

int ik_release_enroll_device(Object devHandle);


7
、调用本地方法

TestJnaLib.INSTANCE.ik_release_enroll_device(devHandle);

 

第三部分:DLL函数对JNA的回调

1dll中定义了如下带回调函数的函数

IRIS_SDK_API int STDCALL ik_init_enroll_module (ik_ipaddress_t   listened_addr,

                                                   int (__stdcall * IK_IDEN_CALLBACK_FUNC)

(IK_IDEN_DEVICE_HANDLE dev_handle// 设备句柄

int type, // 回调类型

void *param); )
红色加粗部分是函数指针。

2
Java部分定义一个回调接口
必须继承自com.sun.jna.Callback接口 (如果回调函数是以stdcall输出,有时候可能引起jvm崩溃,可以改成继承StdCallCallback接口试试,

子接口必须定义单个公有方法或一个名为callback的公有方法。必须持有到回调对象的一个存活引用。一个回调应该不抛出异常。

public interface FunCallBack extends StdCallCallback{

       public int callback(IntByReference devHandle,int type,Pointer para);

}


callback方法里的参数顺序,类型及返回类型必须与C函数的相关类型对应上

3
、定义回调接口的实现

public class CallbackFunImpl implements FunCallBack {

       @Override

       public synchronized int callback(IntByReference devHandle, int type, Pointer para){

      //已知para是指向IkIdenresultArray类型的指针

              IkIdenresultArray ikArray = new IkIdenresultArray(para);

                int count = ikArray.result_count;

                if(ikArray.presult == null || count <= 0){

                    log.info("识别结果数不大于0");

                    return 0;

                }

                IkIdenresult[] rels = (IkIdenresult[])ikArray.presult.toArray(count);

                if (rels == null || rels.length == 0) {

                    log.info("识别结果为空!");

                    return 0;

                }

       }

}

 

上文涉及的结构体的定义如下:

//识别结果列表

    public static class IkIdenresultArray extends Structure{

        public IkIdenresultArray(Pointer p) {

              super(p);

              useMemory(p);

              read();

           }

        

       public IkIdenresultArray() {

           super();

       }

 

       public static class ByReference extends IkIdenresultArray implements Structure.ByReference { }

        public static class ByValue extends IkIdenresultArray implements Structure.ByValue{ }

       

       public IkIdenresult.ByReference presult = new IkIdenresult.ByReference(); // 识别结果列表(表示指针)

        public int result_count ; // 识别结果个数

    }

4
、在表示链接库实现的接口里定义要回调的本地函数

void methodWithCallback(StdCallCallback callback, int left, int right);

本地函数的函数指针用Callback 接口替代。

5
、调用带函数指针的本地函数

TestJnaLib.INSTANCE.methodWithCallback(new CallbackFunImpl(), 4, 6)

最好将标红的地方定义一个static的变量引用它,否则回调函数的内存区域可能被GC回收而引起JVM崩溃,调用如下:

StdCallCallback callback = new CallbackFunImpl();

TestJnaLib.INSTANCE.methodWithCallback(callback, 4, 6)

 

第四部分:JAVAC类型的对应

1、  基本类型的对应可以到网上查找对应表

2、  特殊的struct类型

1>Structure属性传递给本地字段必须是public的。

2>虽然结构体和结构体字段的名字可以是任意的,但他们应该尽可能接近本地定义。参数名及参数顺序对应一样。

3> Structure类的write()方法会把结构体的所有字段固定住,是原生函数可以访问。

4> C语言是不知道你Java的引用的。它只能访问固定的内存地址。因此,在使用JNIJNA时,都会把Java对象锁住。GC不再管理。不删除,也不移动位置。即把传递给Cstruct对象A固定住内存,如果这个A种还嵌套了struct对象,则也被固定住,但是如果嵌套的是struct的引用B,则不会固定,需要把B手动固定,如:

B.ByReference b = new B.ByReference();

b.write();

5> 结构体的定义如:

//识别结果

    public static class IkIdenresult extends Structure{

       //属性都定义为public类型

       public IkIdenresult() {

           super();

       }

       public IkIdenresult(Pointer p) {

           super(p);

           useMemory(p);

           read();

       }

       public static class ByReference extends IkIdenresult implements Structure.ByReference { }//通过ByReference定义的是指针

        public static class ByValue extends IkIdenresult implements Structure.ByValue{ }//通过ByValue定义的是对象

       

        public IntByReference dev_handle; // 识别设备句柄

        public byte []dev_sn = new byte[128];// 设备标志

        public byte []iden_date_time = new byte[32]; // 识别时间

        public int person_id; // personID

        public byte [] person_name= new byte[128]; // 人员姓名

        public int feature_id; // featureID

        public int eye_flag; // 眼睛标志

    }

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics