java使用jna调用c函数
- jna和jni
- 数据类型对应关系
- 编码示例
- c函数:
- jna
jna和jni
JNI允许Java代码和其他语言(尤其C/C++)写的代码进行交互,只要遵守调用约定即可。不过使用JNI调用.dll/.so共享库据说非常痛苦。如果已有一个编译好的.dll/.so文件,如果使用JNI技术调用,我们首先需要使用C语言另外写一个.dll/.so共享库,使用SUN规定的数据结构替代C语言的数据结构,调用已有的 dll/so中公布的函 数。然后再在Java中载入这个库dll/so,最后编写Java native函数作为链接库中函数的代理。经过这些繁琐的步骤才能在Java中调用 本地代码。因此,很少有Java程序员愿意编写调用dll/.so库中原生函数的java程序。
JNA框架解决了既需要编写java代码,又要编写C语言的代理方法及很多数据类型的转换的问题,它提供一组Java工具类用于在运行期动态访问系统本地共享类库而不需要编写任何Native/JNI代码。开发人员只要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射,大大降低了Java调用本体共享库的开发难度。
就开发难度来说,JNA要比JNI简单很多。不过JNA相当于封装后的JNI,可以更方便的调用c/c++函数,但是使用JNA只能单方面调用c/c++函数,使用JNI则可以用Java调用c/c++,或者使用c/c++调用Java
本篇文章只介绍jna的使用方法,不涉及原理部分。需要学习原理的,可以查看文章结尾链接或自行查找。
数据类型对应关系
使用jna调用c/c++函数时,最难的部分是搞清楚参数类型之间的对应关系。本文章主要将参数分为三部分,一类是普通类型,一类是指针类型,最后是输出参数。
普通类型对应关系如下:
java类型 | c类型 | 原生表现 |
byte | char | 8位整数 |
char | wchar_t | 平台依赖 |
short | short | 16位整数 |
int | int | 32位整数 |
long | long long, __int64 | 64位整数 |
float | float | 32位浮点数 |
double | double | 64位浮点数 |
Buffer/Pointer | pointer | 平台依赖(32或64位指针) |
String | char[] |
指针类型需要用到jna 的Pointer类和PointerByReference类。Pointer类代表指向任何东西的指针,PointerByReference类表示指向指针的指针。Pointer类更加通用,事实上PointerByReference类内部也持有Pointer类的实例。
c类型 | jna类型 |
void** | PointerByReference |
void* | Pointer |
char** | PointerByReference |
char& | PointerByReference |
char* | Pointer |
int& | IntByReference |
int* | IntByReference |
char* | String |
char** | String[] |
部分函数涉及到输出参数,或者既是输入,也是输出,部分对照关系如下:
c类型 | jna类型 |
int | IntByReference |
char* | byte[] |
编码示例
c函数:
/**
* \param[OUT] handle - 句柄
* \param[IN] name
* \return 错误码
*/
SA_API int SA_Create(void** handle, const char* name);
/**
* \brief 释放句柄,不在使用时请释放句柄
* \param[IN] hande - 需要释放的句柄
*/
SA_API int SA_Delete(void** handle);
/**
* \param[IN] hande - 已初始化的句柄
* \param[IN] w_path
* \param[IN] device
* \param[IN] a_growth
* \param[IN] r_threshold
* \return 错误码
*/
SA_API int SA_InitDetector(void* handle, const char* w_path, const char* device, char a_growth = 1,
int i_format = 2, float r_threshold = 0.5f);
/**
* \param[IN] hande - 已初始化的句柄
* \param[IN] image
* \param[IN] width
* \param[OUT] result
* \param[IN|OUT] result_length
* \return 错误码
*/
SA_API int SA_DetectAndRecognize(void* handle, const unsigned char* image, int width, char* result,
int* result_length);jna
jna代码主要分为两部分,一个是接口文件,一个是具体的类。
接口定义:
public interface Steel extends Library{
Steel INSTANCE = (Steel) Native.loadLibrary("d:\\SA_Steel.dll", Steel.class);
/**
* \brief 创建句柄,调用以下任意函数前需要先创建句柄
* \param[OUT] handle - 句柄
* \param[IN] name
* \return 错误码
*/
public int SA_Create(PointerByReference pHandle, String name);
/**
* \brief 释放句柄,不在使用时请释放句柄
* \param[IN] hande - 需要释放的句柄
*/
int SA_Delete(PointerByReference pHandle);
/**
* \param[IN] hande - 已初始化的句柄
* \param[IN] w_path
* \param[IN] device
* \param[IN] a_growth
* \param[IN] r_threshold
* \return 错误码
*/
int SA_InitDetector(Pointer Handle, String w_path, String device, int a_growth, float r_threshold ,);
/**
* \param[IN] hande - 已初始化的句柄
* \param[IN] image
* \param[IN] width
* \param[OUT] result
* \param[IN|OUT] result_length
* \return 错误码
*/
int SA_DetectAndRecognize(Pointer handle, byte[] pImg, int width, byte[] result, IntByReference i);
}类:
public class Test{
public static void main(String[] args) {
PointerByReference pHandle = new PointerByReference();
int ret= Steel.INSTANCE.SA_Create(pHandle, "R");
ret= Steel.INSTANCE.SA_InitDetector(pHandle.getValue(), "d://SA_3.dll", "GPU", 1, 0.4f);
byte[] byteArr = "".getBytes();
byte[] pointerByReference=new byte[35];
IntByReference intByReference=new IntByReference();
intByReference.setValue(35);
int width = 0;
ret= Steel.INSTANCE.SA_DetectAndRecognize(pHandle.getValue(), byteArr, width,
pointerByReference, intByReference);
//举例,若需要接收输出类型的参数,以int为例,获取IntByReference或PointerByReference的值时,调用getValue()方法
IntByReference width=new IntByReference();
ret=Steel.INSTANCE.SA_LastDetectedRect(pHandle.getValue(),width);
System.out.println("width:"+width.getValue());
Steel.INSTANCE.SA_Delete(pHandle);
}jna的jar包可以去阿里云的maven库下载,附地址maven仓库
参考文章:void**、void*、char**、char*、int*等类型映射关系及简单示例参考文章:关于(void**)&的理解参考文章:java通过jna调用dll文件参考文章:JNA简介及使用参考文章:深入浅出JNA-快速调用原生函数
















