jnaerator:JNA框架下向动态库传递Java Object(即动态库JNI方式访问java对象)

熟悉JNA的童鞋都知道,通过JNA可以向动态库传递(或从动态库返回)com.sun.jna.Structure为基类的对象,在动态库一层,会把Structure解析为结构C语言的structunion,jnaerator可以将C语言定义的structunion自动生成继承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);
	}

Guess you like

Origin blog.csdn.net/10km/article/details/116497524