欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JNA 相关问题

程序员文章站 2022-04-28 15:16:54
JNA 相关问题 结构体对齐问题 要注意调用的c库字段对齐方式的相关设置。 jna中提供了4种对齐方式: 需要在相应的结构体构造函数中加入 设置对应的对齐方式。 unsigned类型处理 java中没有对应的无符号类型,需要进行相应的转换,以byte类型为例(c中的 unsigned char) c ......

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对象。

参考文件