jna jni
我最近偶然发现了一个不错的框架,如果您不得不使用本机代码的话,您会喜欢的。 在此框架之前,如果需要调用本机代码,则可以使用JNI 。 JNI使用了一个经过验证的但复杂且容易出错的过程。
首先,您像往常一样编写Java类。 但是对于要委派给本机代码的方法,可以使用native
关键字,而不提供实现。 然后,您调用JDK提供的名为javah的可执行文件。 这将生成您的C头文件(* .h)和一个空的存根实现:您必须填补空白。 最后,您将同时编译Java和C文件。
在运行时,不要忘记使用System.loadLibrary("mylib")
加载库。 请注意,您没有提供扩展名,JVM会根据您的平台(Windows上的.dll
,Linux上的.so
)自动为您提供扩展名。 然后调用Java类,它将神奇地委托给您的本机代码。
由于以下原因,整个过程总是让我感到沮丧(因此,我可以想象,很多开发人员):
- 因为我是Java开发人员,而不是C开发人员,所以我永远无法编写出色的C代码。 甚至考虑内存分配或让我自己思考函数指针都伤了我的头head
- 如果需要更改本机Java方法签名,则必须再次运行整个过程,或者无错误地更改标头和C文件,然后再次编译所有内容。 在这种情况下,我不能强调拥有非常自动化的构建过程或适当的IDE的重要性(我倾向于前者)
- 最后但并非最不重要的一点是,如果我无权访问源C文件怎么办? JNI无法帮助您调用Windows dll ...否则您必须编写类似代理的C文件
让人们高兴。 Java.net为您带来了解决方案。 问题的答案是Java Native Access或JNA。 现在,调用NTLM身份验证或在应用程序中显示正在运行的服务将变得轻而易举。 让我们尝试获取有关在Windows下运行的计算机的信息-抱歉,'Nix用户。
首先是要知道哪个功能可以带您到达那里:这就是MSDN库的目标。 现在,创建一个接口,最好在您将使用的DLL之后命名,并使其继承自com.sun.jna.Libray
。 它的方法必须精确映射DLL的名称和参数。 例如,假设您要显示计算机的名称。 在Windows下, kernel32.dll
提供了一种名为GetComputerNameW()
的方法。 因此,您的接口将具有一个名为GetComputerNameW()
。 细节中的魔鬼,您必须将MSDN中记录的每个参数映射到接口方法签名中的一个参数上。 GetComputerNameW()
具有2个参数: LPTSTR
(指向char缓冲区的指针)和LPDWORD
(指向整数的指针)。 运行到JNA文档,Java中的映射成为char[]
和com.sun.jna.ptr.IntByReference
。
您的界面现在如下所示:
publicinterfaceKernel32extendsStdCallLibrary{
intGetComputerNameW(char[]name,IntByReferencenumber);
// Other method mappings
...
}
现在,为了访问Kernel32引用,只需使用以下代码行。 在表格下,它将通过代理将我们的接口绑定到基础实现:
Kernel32kernel32=(Kernel32)Native.loadLibrary("kernel32",Kernel32.class);
完成此操作后,每次对kernel32的GetComputerName()
方法的GetComputerName()
都将用我们计算机的名称填充char缓冲区。
JNA仍然存在一些缺点:
- JNA的执行速度通常比JNI慢10倍。 它具有一些加快执行速度的技术,因此,如果您处于性能感知环境中,则可能需要使用它们。
- 它不会使您成为专业的C程序员,因此非常复杂的方法签名将使您陷入疯狂:这项工作最困难的部分是将数据类型从C映射到Java。 这可能会让您
java.lang.UnsatisfiedLinkError: Error looking up function XXX: La procédure spécifiée est introuvable
因为您将看到java.lang.UnsatisfiedLinkError: Error looking up function XXX: La procédure spécifiée est introuvable
经常是可java.lang.UnsatisfiedLinkError: Error looking up function XXX: La procédure spécifiée est introuvable
。 在这种情况下,请致电C程序员寻求帮助!
该人士这个小项目提供Maven风格。 玩Java和Windows!
jna jni