JNA 相关问题
jna 相关问题
结构体对齐问题
要注意调用的c库字段对齐方式的相关设置。
#pragma pack (push,1) #pragma pack(pop)
jna中提供了4种对齐方式:
/** use the platform default alignment. */ public static final int align_default = 0; /** no alignment, place all fields on nearest 1-byte boundary */ public static final int align_none = 1; /** validated for 32-bit x86 linux/gcc; align field size, max 4 bytes */ public static final int align_gnuc = 2; /** validated for w32/msvc; align on field size */ public static final int align_msvc = 3;
需要在相应的结构体构造函数中加入super(align_none);
设置对应的对齐方式。
unsigned类型处理
java中没有对应的无符号类型,需要进行相应的转换,以byte类型为例(c中的 unsigned char)
public class util { public static byte sendunsignedbyte(int input){ return (byte) (input & 0xff); } public static int receiveunsignedbyte(byte input){ return input & 0xff; } }
char
const char 作为函数参数,可以直接用字符串string
传值。
char** 函数回传字符串。用pointerbyreference
char** 发送数据到struct的char**
类型的字段中:new stringarray(string[] strings);
获取struct中的char**
类型回传的数据: string[] getstringarray(long offset, int length)
final pointerbyreference ptrref = new pointerbyreference(); final pointer p = ptrref.getvalue(); final string val = p.getstring(0);
获取数据,内存由c分配,那么需要c同时提供jni接口释放获取到的内存。
发送数据:
string strinfo = "very nice"; byte[] binfo = strinfo.getbytes(); memory info = new memory(binfo.length + 1); info.clear(); info.write(0,binfo,0,binfo.length); info.setbyte(binfo.length,(byte)0); p.info = info;
struct 数组
获取数据,要调用c的接口释放分配的内存
传递数组到c:
关键方法:public structure[] toarray(int size)
用于在java中分配内存,和把c中获取的内存空间转化为structure
数组.
callback
typedef void(*callback)(person*);
public static class showcallback implements callback{ public void invoke(person.byreference person){ string name = ""; byte[] data = person.name; int count = data.length; for(int i=data.length - 1;i>= 0;i--){ if(data[i] != 0) { break; } count--; } if(count > 0) { byte[] copy = new byte[count]; system.arraycopy(data,0,copy,0,count); name = new string(copy); } system.out.println("callback name\t"+name); } }
用byte[]数组值给char[]
由于c中字符串以\0
结尾,因此需要在末尾多分配一个字节的空间,并把这个末尾字节设置为0
byte[] binfo = strinfo.getbytes(); memory info = new memory(binfo.length + 1); info.write(0,binfo,0,binfo.length); info.setbyte(binfo.length,(byte)0);
jvm异常退出
jna也提供了一种保护机制。比如防止jna出现异常不会导致jvm异常退出,默认是开启这个功能的,开启方式为 system.setproperty("jna.protected","true"); 记得要在jna加载库文件之前调用,然后try {...} catch(throwable e)异常,出现”非法内存访问”的时候依然会导致jvm退出。
函数调用约定
_stdcall和_cdecl函数调用约定
_cdecl,是c语言缺省的调用约定,参数采用从右到左的压栈方式,函数本身不清理堆栈,调用者负责清理堆栈。对于这种库,只要直接继承library。
_stdcall,是pascal程序的缺省调用方式,win32 api都采用_stdcall调用方式。参数采用从右到左的压栈方式,被调函数自身在返回前清空堆栈。这种需要继承stdcalllibrary。
如果用cpp实现库,需要调用的函数申明添加extern "c"
#pragma pack(push,1) //紧凑型对齐 #ifdef __cplusplus extern "c" { #endif typedef void(*callback)(person*); void show(person* person,const callback cb); // ...更多的方法 #ifdef __cplusplus } #endif #pragma pack(pop)
柔性数组成员(flexible array member)
struct blob { size_t length; unsigned char data[]; };
class blob extends structure { int length; byte[] data = new byte[1]; public blob(int length) { this.length = length; this.data = new byte[length]; allocatememory(); } public blob(pointer p) { super(p); this.length = p.readint(0); this.data = new byte[this.length]; read(); } }
strucure
内存大小在java中有改动后需要及时调用allocatememory()
重新分配内存. write()
方法把strucure
对象的改动及时写入到本地内存中,read()
重新把本地内存中的数据读取到strucure
对象。
参考文件
上一篇: 第八节--访问方式
下一篇: C++中的自定义内存管理