JNA 传参char[] 和结构体等

近日项目中须要用java调用c/c++编写的dll库,全部了解到jna这个东东,下面是使用的一些经验:java

1、java使用Jna须要两个jar包,eg:jna-3.5.1.jar和platform-3.5.1.jar 下载地址,添加完依赖包后把需调用的dll放到项目根目录下就是和src同级目录下c++

2、报错:Unable to load DLL 'xxx.dll': 找不到指定的模块,可能有一下几个问题:数组

     一、使用的jdk和dll位数不一样,64位的jdk只能调用64位的dll,32同样。函数

     二、dll的位置放的不对(也有说放在c盘的systen32下的)测试

  三、电脑缺乏dll依赖的组件(例如我重装完系统怎么调用都不成功,最后发现缺乏了Visual C++ Redistributable Packages for Visual Studio 2013这个组件 下载地址,也有多是其余组件能够用VS的插件查看,具体请百度)编码

3、java-c 数据类型映射   jna操做文档 下载地址spa

常见的映射就不说了,这里说一下我项目中用到的:.net

一、char*&插件

//dll中
int pack_clou102(char*& sendstr)

//java中接口    PointerByReference 表示指针的引用类型
public int pack_clou102(PointerByReference send);

//获取send      
String str = send.getValue().getString(0);
//send.getValue()获取的是一个指针   而getString(0)是获取指针的值   这里不能够用
 send.getValue().toString()//会致使乱码

二、char*指针

//根据dll的操做来决定,官方char*对应String

//可是下面这个例子中用byte[]才能够

//dll中
//UINT8是指无符号8位二进制整型  在这里映射String会出现编码问题的,因此这里用byte[]
int unpack_clou102(char* recvbuf)
{
	UINT8* pbuf = (UINT8*)recvbuf;   
	UINT8 ucCheckSum = 0;// 校验和

。。。
}

//java中
 public int unpack_clou102(byte[] recvbuf);

三、传参char[]

//dll
int pack_clou102(char[20] send){
。。。
return 0;
}
//有时候会遇到dll中用char[]传字符串的,java中是用byte[],这时候能够借用“”.getbytes()
//jna
byte[20] bytes = "2016-08-29 11:06:23".getbytes();
int mun = pack_clou102(bytes);

四、传参结构体    能够参考  原文地址

//DLL中
struct
CompanyStruct{ long id; wchar_t* name; UserStruct* users[100]; int count; };
//java中
public
static class CompanyStruct2 extends Structure{   public NativeLong id;   public WString name;   public UserStruct.ByReference[] users=new UserStruct.ByReference[100];   public int count; }
//测试代码
CompanyStruct2.ByReference companyStruct2=new CompanyStruct2.ByReference(); companyStruct2.id=new NativeLong(2); companyStruct2.name=new WString("Yahoo"); companyStruct2.count=10; UserStruct.ByReference pUserStruct=new UserStruct.ByReference(); pUserStruct.id=new NativeLong(90); pUserStruct.age=99; pUserStruct.name=new WString("杨致远"); // pUserStruct.write(); for(int i=0;i<companyStruct2.count;i++){ companyStruct2.users[i]=pUserStruct; } TestDll1.INSTANCE.sayCompany2(companyStruct2);

 

执行测试代码,报错了。这是怎么回事?考察JNI 技术,咱们发现Java 调用原生函数时,会把传递给原生函数的Java 数据固定在内存中,这样原生函数才能够访问这些Java 数据。对于没有固定住的Java 对象,GC 能够删除它,也能够移动它在内存中的位置,以使堆上的内存连续。若是原生函数访问没有被固定住的Java 对象,就会致使调用失败。固定住哪些java 对象,是JVM 根据原生函数调用自动判断的。而上面的CompanyStruct2结构体中的一个字段是UserStruct 对象指针的数组,所以,JVM 在执行时只是固定住了CompanyStruct2 对象的内存,而没有固定住users 字段引用的UserStruct 数组。所以,形成了错误。咱们须要把users 字段引用的UserStruct 数组的全部成员也所有固定住,禁止GC 移动或者删除。若是咱们执行了pUserStruct.write();这段代码,那么就能够成功执行上述代码。Structure 类的write()方法会把结构体的全部字段固定住,使原生函数能够访问。

相关文章
相关标签/搜索