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

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

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

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

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

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

三、java-c 数据类型映射   jna操作文档 下载地址

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

1、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()//会导致乱码

2、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);

3、传参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);

4、传参结构体    可以参考  原文地址

//DLL中
struct CompanyStruct{
long id;
wchar_t* name;
UserStruct* users[];
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()方法会把结构体的所有字段固定住,使原生函数可以访问。

JNA 传参char[] 和结构体等的更多相关文章

  1. c++调用python系列(1): 结构体作为入参及返回结构体

    最近在打算用python作测试用例以便对游戏服务器进行功能测试以及压力测试; 因为服务器是用c++写的,采用的TCP协议,当前的架构是打算用python构造结构体,传送给c++层进行socket发送给 ...

  2. C语言复习:结构体

    结构体专题 01.结构体类型定义及结构体变量定义     char c1,char c2, char name[62]; int age     char name[62]; int age,char ...

  3. p/invoke碎片,对结构体的处理

    结构体的一些相关知识 可直接转换类类型,比如int类型,在托管代码和非托管代码中占据内存大小 和意义都是一个样的. 结构体封送的关键是:在托管代码和非托管代码中定义的一致性.什么是定义的一致性?包括结 ...

  4. 关于C语言结构体,指针,声明的详细讲解。——Arvin

    关于结构体的详细分析 只定义结构体 struct Student { int age; char* name; char sex;//结构体成员 };//(不要忘记分号) Student是结构体的名字 ...

  5. 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符

    [源码下载] 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 结构体 ...

  6. c语言结构体指针初始化

    今天来讨论一下C中的内存管理. 记得上周在饭桌上和同事讨论C语言的崛起时,讲到了内存管理方面 我说所有指针使用前都必须初始化,结构体中的成员指针也是一样 有人反驳说,不是吧,以前做二叉树算法时,他的左 ...

  7. C++结构体中sizeof

    说明: 结构体的sizeof值,并不是简单的将其中各元素所占字节相加,而是要考虑到存储空间的字节对齐问题.这些问题在平时编程的时候也确实不怎么用到,但在一些笔试面试题目中出是常常出现,一.解释 现代计 ...

  8. C语言结构体指针初始化(转)

    reference: https://www.cnblogs.com/losesea/archive/2012/11/15/2772526.html 今天来讨论一下C中的内存管理. 记得上周在饭桌上和 ...

  9. C 语言结构体之点运算符( . )和箭头运算符( -> )的区别

    很多时候,在对结构体进行相应的编码时,时而发现是用点运算符( . ),时而是用箭头运算符( -> ):那么这两者之间的使用有什么区别么? 相同点:两者都是二元操作符,而且右边的操作数都是成员的名 ...

随机推荐

  1. Data Structure Array: Given an array arr[], find the maximum j – i such that arr[j] > arr[i]

    http://www.geeksforgeeks.org/given-an-array-arr-find-the-maximum-j-i-such-that-arrj-arri/ #include & ...

  2. Data Structure Array: Find the Missing Number

    http://www.geeksforgeeks.org/find-the-missing-number/ 1. use sum formula, O(n), O(1) 2. use XOR, O(n ...

  3. [原创]java WEB学习笔记20:MVC案例完整实践(part 1)---MVC架构分析

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  4. POJ Layout

    A - Layout Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit S ...

  5. 关于spring事务注解

    关于事务的注解常用如下1.如果有事务, 那么加入事务, 没有的话新建一个(默认情况下),也就是当我们要开启事务的时候才用,即有数据库有增删改操作@Transactional(rollbackFor=E ...

  6. QQ.PC管家进程

    1.家里的笔记本 WIn7x64 C:\Program Files (x86)\Tencent\QQPCMgr\12.10.19266.225\QMDL.exeC:\Program Files (x8 ...

  7. 日期工具类 DateUtils(继承org.apache.commons.lang.time.DateUtils类)

    /** * */ package com.dsj.gdbd.utils.web; import org.apache.commons.lang3.time.DateFormatUtils; impor ...

  8. QTableWidget设计原则

    一.组成结构: 列表控件由水平表头(self.horizontalHeader()).垂直表头(self.verticalHeader())和单元格(QTableWidgetItem)组成 其中表头又 ...

  9. linux命令学习笔记(4):mkdir命令

    linux mkdir 命令用来创建指定的名称的目录,要求创建目录的用户在当前目录中具有写权限, 并且指定的目录名不能是当前目录中已有的目录. .命令格式: mkdir [选项] 目录... .命令功 ...

  10. [原]NYOJ-光棍的yy-655

    大学生程序代写 http://acm.nyist.net/JudgeOnline/problem.php?pid=655 光棍的yy 时间限制:1000 ms  |  内存限制:65535 KB 难度 ...