jnaerator:JNA框架下向动态库传递Java Object(即动态库JNI方式访问java对象)
Posted 10km
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jnaerator:JNA框架下向动态库传递Java Object(即动态库JNI方式访问java对象)相关的知识,希望对你有一定的参考价值。
熟悉JNA的童鞋都知道,通过JNA可以向动态库传递(或从动态库返回)com.sun.jna.Structure
为基类的对象,在动态库一层,会把Structure
解析为结构C语言的struct
或union
,jnaerator可以将C语言定义的struct
或union
自动生成继承Structure
的 java类。
但有的时候,我们希望java层与动态库直接传递Java对象,动态库以JNI方式访问java层传递的Java对象,或直接返回java对象给java层,JNA可以实现么?
最近我就遇到了这个问题,研究了JNA的代码后,发现JNA框架默认是不是允许直接传递java对象的。但可以通过指定特定的选项实现java对象的传递。
OPTION_ALLOW_OBJECTS
JNA中在调用一个native函数时是可以指定一些特别选项的。如下是com.sun.jna.Function
类的invoke
系列方法的其中一个定义,其中options
参数允许指定函数调用时的一些特别要求:
这些特别要求中就有一个我们本次任务中要用到的选项:
com.sun.jna.Library.OPTION_ALLOW_OBJECTS
该选项是个布尔值,为true时允许任何Java对象作为输入参数或返回值。只有在调用函数时显式指定OPTION_ALLOW_OBJECTS
为true才生效。
示例
怎么使用OPTION_ALLOW_OBJECTS
选项呢?
以下以在我的项目中的实际应用代码举例说明。
下面是我在动态库中定义的一个函数
// @param env JNIEnv 结构,JNI方式访问Java对象必须要有它
// @param arg 输入Java 对象
// @param msg 输入字符串
// @return 返回Java对象
void* meg_obj_arg(void *env, void* arg, const char*msg);
下面为JNA生成的 library接口方法
/**
* Original signature : <code>void* meg_obj_arg(void*, void*, const char*)</code><br>
* <i>native declaration : src/cpp/megauth/megauth.h:116</i>
*/
Pointer meg_obj_arg(Pointer env, Pointer arg, String msg);
然而我们并不能直接使用这个接口方法。因为我们无法将一个Object转为Pointer对象
正确的做法如下:
/**
* JNA传递Java对象测试
*/
@Test
public void testObjectArg(){
// 创建一个map对象,将 OPTION_ALLOW_OBJECTS指定为true
Map<String, Boolean> options = new HashMap<>();
options.put(Library.OPTION_ALLOW_OBJECTS,Boolean.TRUE);
// 调用getFunction方法返回函数对象
// 在这里,MegauthLibrary 为JNAerator生成的接口类,名字是你自己定义的哦。
Function meg_obj_arg = MegauthLibrary.JNA_NATIVE_LIB.getFunction("meg_obj_arg");
// 调用invoke方法,注意这里要用 com.sun.jna.JNIEnv.CURRENT 对象代替实际的动态库访问java对象所需要的JNIEnv结构
Class<?> ret = (Class<?>) meg_obj_arg.invoke(
/** 返回值类型 */
Class.class,
/** 向动态传递的输入参数,与动态中的函数定义一致 */
new Object[]{ JNIEnv.CURRENT,new StringBuilder()} ,
/** 调用选项 */
options);
System.out.printf("return %s\\n",ret);
}
以上是关于jnaerator:JNA框架下向动态库传递Java Object(即动态库JNI方式访问java对象)的主要内容,如果未能解决你的问题,请参考以下文章