工欲善其事,必先利其器,本篇文章就来详细探讨在JNA开源项目的工程中提供了哪些应用接口,它们分别提供了怎样的功能。
JNA4.1.0的包结构如下所示:
com.sun.jna
com.sun.jna.platform
com.sun.jna.platform.dnd
com.sun.jna.platform.mac
com.sun.jna.platform.unix
com.sun.jna.platform.win32
com.sun.jna.platform.win32.COM
com.sun.jna.platform.win32.COM.tlb
com.sun.jna.platform.win32.COM.tlb.imp
com.sun.jna.platform.wince
com.sun.jna.ptr
com.sun.jna.win32
这些包结构的功能可以分为三个大类,下面来一一介绍。
一 Java本地访问
com.sun.jna
提供了简化的本地库的访问。
com.sun.jna.ptr
提供各种本地指针到类型(*)表示。
com.sun.jna.win32
提供所需的Windows平台上标准的API类型和功能映射器。
1.1 JNA加载
JNA包括一个小型的,特定于平台的共享库,使所有本地访问。当第一次访问本机类,JNA将首先尝试加载从jna.boot.library.path指定的目录这个库。如果失败,它会掉下来的系统库的路径返回装货。最后,它会尝试从JNA的jar文件中提取存根库,并加载它。
该jna.boot.library.path属性主要是为了支持jna.jar被列入-Xbootclasspath,那里的java.library.path和LD_LIBRARY_PATH被忽略。这也是用于指定版本的库优先使用任何可能已在系统上安装有用。
从系统加载不能jna.nosys = true来禁止,并从jar文件解压缩可以通过jna.nounpack = true来禁用。
用于搜索JNA的本机库的库名可通过设定jna.boot.library.name,默认为“jnidispatch”来改变。如果你的系统需要共享库的唯一名称(而不是唯一的路径)也可能是有用的设置这个值,如果你的系统必须存储在同一目录下不同版本的JNA共享库(例如,用于不同的架构)。
1.2 库映射
当你确定哪些共享库保存的方法,你需要访问,创建对应于该库的类。例如,对于C库映射本身看起来像下列之一:
// Alternative 1: interface-mapped class, dynamically load the C library
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)Native.loadLibrary("c", CLibrary.class);
}
// Alternative 2: direct-mapped class
public class CLibrary {
static {
Native.register("c");
}
}
传递给Native.loadLibrary(字符串,类)(或NativeLibrary.getInstance(字符串))方法的字符串是共享库文件的未装饰名称。下面是库名称映射的一些例子:
具有唯一的文件系统路径的任何给定的本机库由NativeLibrary的一个实例表示,并且经由NativeLibrary.getInstance(字符串)获得。当不再受任何Java代码中引用的本机库将被卸载。
如果库名称为空,你的映射会应用到当前进程,而不是一个单独装入的库。这可能有助于避免冲突,如果有多个不兼容的版本可用的库。
加载的本地库的搜索路径可以通过设置jna.library.path和一些其他属性进行修改。您也可以在JAR文件中捆绑本机库,并有自动JNA提取它们的负载。见NativeLibrary了解详细信息。
1.3 函数映射
函数名是直接从他们的Java接口名称映射到本地库导出的符号。例如,该功能为ASCII字符串转换为整数是这样的:
public interface CLibrary extends Library {
int atol(String s);
}
或者,你可以直接映射到一个声明本地方法:
public class CLibrary {
public static native int atol(String s);
}
如果你喜欢重命名Java方法,以符合Java编码约定,那么你就可以在提供的选项中的条目(Library.OPTION_FUNCTION_MAPPER/ FunctionMapper)地图传给Native.loadLibrary(),它映射Java名称的本地名称。虽然这样可以使你的Java代码显得简洁,名称的其他映射可能使其少一些明显的被称为原生功能。
通过与NativeLibrary实例中获得的功能类的一个实例。这个功能实例处理参数编组代表团原生功能。
1.4 类型映射
Java类型必须选择符合本地类型相同的大小。以下是由JNA库支持的类型:
无符号值可以通过分配对应二进制补码表示为相同大小的符号类型予以通过。
基本类型的Java阵列可以由缓冲器,以访问该阵列的一个子集被包裹(改变有效尺寸和/或offest)。
原始类型的Java数组只适用于单一的通话范围内使用。如果本机代码保持一个参考的内存,使用内存或缓冲液代替。
原始数组和结构作为结构成员都覆盖在母体结构存储器。
位域必须手动装入一个整数类型。
所有其他类型的最终必须被转换为在该表中的类型之一。方法与参数或类型比这些必须使用从类型或NativeMapped供应类型转换信息导出为不支持其他类型的返回值。
类型映射行为可以通过初始化库接口时,提供了一个TypeMapper为Library.OPTION_TYPE_MAPPER选项来进行定制。见W32APITypeMapper的例子,它提供布尔和字符串类型的自定义转换。您可以自由使用任何类型方便您定义的接口,但是所有的自定义类型必须提供一个映射到上面所列的基本或派生类型之一。
类型映射也可