JNA的简单使用
2015-12-17 11:18
615 查看
以前从效率上考虑,做native调用都是通过jni实现,其中的一些障碍我想开发过jni的人都知道,比如你要复用老的代码库,为了适应Jni的机制需要再做一次封装,这其中要涉及到jni的内存管理规则,和Java代码的交互,数据类型的转换,在c/c++复杂数据类型上是很棘手的。当然这些都是可以解决的,就看个人的开发思路。
近日研究了JNA(java native access),这种机制调用dll,so相对于Jni是非常方便的,你不用再做wrapper,做到只要有头文件你想调用那个接口就声明那个接口(做过.net的人是很熟悉的),当然这种好用的模式需要你下载jna.jar这个包加入你的project,说穿了别人为你做了很多转换的工作,效率肯定没有直接调用jni高。
下面就怎么使用JNA做说明,涉及到java代码调用native、native回调java代码(回调是很有用的,存在于很多库中!)、结构体参数的使用(感谢jna.jar的开发者,如果dll,so接口是自己设计的请避免结构体、复杂数据结构!)。
我的测试环境是win7 32bit旗舰版 + ecplise + jdk1.7, jna.jar请自行下载,网上很多。
1.需要引用的类,可以根据自己的情况而定。
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Callback; // 如果是cdecl模式回调要用
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.win32.StdCallLibrary.StdCallCallback;// stdcall回调模式要用
2.在Interface中声明要调用的接口(截取的主体代码)。
// 登录接口使用的结构体java声明
public static class LoginInfo extends Structure {
public static class ByValue extends LoginInfo implements Structure.ByValue {} // 这行很重要,否则你的数据到了native中完全是乱码
public byte user[] = new byte[64];
public byte pwd[] = new byte[64];
public byte host[] = new byte[64];
public int port;
}
// 声明natvie中的接口
public interface CDeviceAPI extends Library
// 如果接口是stdcall约定请使用 StdCallLibrary
{
// event
call interface
interface JavaCallbackEvent extends StdCallCallback// 如果回调函数是stdcall约定使用这种模式,否则使用与之对应的
{
void CallbackEvent(int type, Pointer pUser);// Pointer转c的void*
}
int init();
int cleanup();
int GetAPIVer();
int Login(LoginInfo.ByValue info);
int Logout(int userid);
int set_event_callback(int userid, JavaCallbackEvent cbfun, Pointer pUser);
}
3.上面已经完成了部分接口的声明,下面实际的调用。
// 加载dll、so,Windows环境下直接放入工程目录下即可,like unix环境放入/lib或者usr/lib即可。
CDeviceAPI lib = (CIPCAPI)Native.loadLibrary("testlib", CDeviceAPI .class);
CDeviceAPI .JavaCallbackEvent cbEvent = new CDeviceAPI .JavaCallbackEvent() {
@Override
public void CallbackEvent(int type, Pointer pUser) {
// TODO Auto-generated method stub
System.out.println("Java layer Event=" + type);
}
};
long ver = lib.GetAPIVer();
System.out.println("ver=" + ver);
// init
lib.init();
// login data
LoginInfo.ByValue info = new LoginInfo.ByValue();
info.user = new byte[64];
for(int i=0; i < "admin".length(); i++) {
info.user[i] = (byte) "admin".charAt(i);
}
userid = lib.Login(info, 1);
System.out.println("userid=" + userid);
lib.set_event_callback(userid, cbEvent, null);// 设置回调
System.out.println("wait to connect device.");
Thread.sleep(20000);
lib.cleanup(userid);
4。以上1,2,3点就是核心代码,其实只要关注c,java/jna数据类型的转换,结构体的转换,回调,接口参数入栈的约定,开发就基本没有什么问题。
jna开发确实比jni方便,如果适合自己的项目建议使用,毕竟jni加个native api Java层就要改的麻烦没有了。
如果你的接口有很多结构体参数,那不管是jni,jna在java层表达都比较麻烦,建议使用json好些。
Java—C和操作系统数据类型的对应表
近日研究了JNA(java native access),这种机制调用dll,so相对于Jni是非常方便的,你不用再做wrapper,做到只要有头文件你想调用那个接口就声明那个接口(做过.net的人是很熟悉的),当然这种好用的模式需要你下载jna.jar这个包加入你的project,说穿了别人为你做了很多转换的工作,效率肯定没有直接调用jni高。
下面就怎么使用JNA做说明,涉及到java代码调用native、native回调java代码(回调是很有用的,存在于很多库中!)、结构体参数的使用(感谢jna.jar的开发者,如果dll,so接口是自己设计的请避免结构体、复杂数据结构!)。
我的测试环境是win7 32bit旗舰版 + ecplise + jdk1.7, jna.jar请自行下载,网上很多。
1.需要引用的类,可以根据自己的情况而定。
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Callback; // 如果是cdecl模式回调要用
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.win32.StdCallLibrary.StdCallCallback;// stdcall回调模式要用
2.在Interface中声明要调用的接口(截取的主体代码)。
// 登录接口使用的结构体java声明
public static class LoginInfo extends Structure {
public static class ByValue extends LoginInfo implements Structure.ByValue {} // 这行很重要,否则你的数据到了native中完全是乱码
public byte user[] = new byte[64];
public byte pwd[] = new byte[64];
public byte host[] = new byte[64];
public int port;
}
// 声明natvie中的接口
public interface CDeviceAPI extends Library
// 如果接口是stdcall约定请使用 StdCallLibrary
{
// event
call interface
interface JavaCallbackEvent extends StdCallCallback// 如果回调函数是stdcall约定使用这种模式,否则使用与之对应的
{
void CallbackEvent(int type, Pointer pUser);// Pointer转c的void*
}
int init();
int cleanup();
int GetAPIVer();
int Login(LoginInfo.ByValue info);
int Logout(int userid);
int set_event_callback(int userid, JavaCallbackEvent cbfun, Pointer pUser);
}
3.上面已经完成了部分接口的声明,下面实际的调用。
// 加载dll、so,Windows环境下直接放入工程目录下即可,like unix环境放入/lib或者usr/lib即可。
CDeviceAPI lib = (CIPCAPI)Native.loadLibrary("testlib", CDeviceAPI .class);
CDeviceAPI .JavaCallbackEvent cbEvent = new CDeviceAPI .JavaCallbackEvent() {
@Override
public void CallbackEvent(int type, Pointer pUser) {
// TODO Auto-generated method stub
System.out.println("Java layer Event=" + type);
}
};
long ver = lib.GetAPIVer();
System.out.println("ver=" + ver);
// init
lib.init();
// login data
LoginInfo.ByValue info = new LoginInfo.ByValue();
info.user = new byte[64];
for(int i=0; i < "admin".length(); i++) {
info.user[i] = (byte) "admin".charAt(i);
}
userid = lib.Login(info, 1);
System.out.println("userid=" + userid);
lib.set_event_callback(userid, cbEvent, null);// 设置回调
System.out.println("wait to connect device.");
Thread.sleep(20000);
lib.cleanup(userid);
4。以上1,2,3点就是核心代码,其实只要关注c,java/jna数据类型的转换,结构体的转换,回调,接口参数入栈的约定,开发就基本没有什么问题。
jna开发确实比jni方便,如果适合自己的项目建议使用,毕竟jni加个native api Java层就要改的麻烦没有了。
如果你的接口有很多结构体参数,那不管是jni,jna在java层表达都比较麻烦,建议使用json好些。
Java—C和操作系统数据类型的对应表
Java Type | C Type | Native Representation |
boolean | int | 32-bit integer (customizable) |
byte | char | 8-bit integer |
char | wchar_t | platform-dependent |
short | short | 16-bit integer |
int | int | 32-bit integer |
long | long long, __int64 | 64-bit integer |
float | float | 32-bit floating point |
double | double | 64-bit floating point |
Buffer Pointer | pointer | platform-dependent (32- or 64-bit pointer to memory) |
<T>[] (array of primitive type) | pointer array | 32- or 64-bit pointer to memory (argument/return) contiguous memory (struct member) |
除了上面的类型,JNA还支持常见的数据类型的映射。 | ||
String | char* | NUL-terminated array (native encoding or jna.encoding) |
WString | wchar_t* | NUL-terminated array (unicode) |
String[] | char** | NULL-terminated array of C strings |
WString[] | wchar_t** | NULL-terminated array of wide C strings |
Structure | struct* struct | pointer to struct (argument or return) (or explicitly) struct by value (member of struct) ( or explicitly) |
Union | union | same as Structure |
Structure[] | struct[] | array of structs, contiguous in memory |
Callback | <T> (*fp)() | function pointer (Java or native) |
NativeMapped | varies | depends on definition |
NativeLong | long | platform-dependent (32- or 64-bit integer) |
PointerType | pointer | same as Pointer |
相关文章推荐
- ionic 组件之二维码扫描
- left 和 margin-left
- 使用nginx为ArcGIS Server做反向代理
- java资料——线性表(转)
- Spring 配置log4j和简单介绍Log4J的使用
- java.io.FileNotFoundException: class path resource [META-INF/xfire/services.xml] cannot be opene
- RxJava随记
- procedure在Mysql和Sql Server中使用的一些区别
- grep 命令
- What is the difference between arguments and parameters?
- Raphael的鼠标over move out事件
- canvas arc()方法详解
- 市 区 分级显示marker
- error1062 ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry ’1′ for
- MyEclipse 怎样手动编译整个项目
- LeetCode OJ : 6 ZigZag Conversion
- Universal-Image-Loader 原理和实现
- UISlider的使用
- poolingHttpclientConnectionmanager 使用
- DELL服务器iDRAC相关设置