近日项目中需要用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. 【LeetCode】:二叉搜索树

    相关概念: 一棵二叉搜索树(BST)是以一棵二叉树来组织的,可以用链表数据结构来表示,其中,每一个结点就是一个对象,一般地,包含数据内容key和指向孩子(也可能是父母)的指针属性.如果某个孩子结点不存 ...

  2. 回忆基础:制作plist文件

    -(void)creatPlistFileWithArr:(NSArray *)array{ //将字典保存到document文件->获取appdocument路径 NSString *docP ...

  3. PHP新写的大转盘抽奖源码

    中奖概率 抽奖大转盘演示:http://www.sucaihuo.com/php/3301.html function getRand($proArr, $proCount) { $result = ...

  4. 算法(Algorithms)第4版 练习 1.3.37

    package com.qiusongde.creative; import com.qiusongde.Queue; import edu.princeton.cs.algs4.StdOut; pu ...

  5. redis实现session共享,哨兵

    一.Redis介绍 1.redis是key-value的存储系统,属于非关系型数据库 2.特点:支持数据持久化,可以让数据在内存中保存到磁盘里(memcached:数据存在内存里,如果服务重启,数据会 ...

  6. 在解析XML时要注意解析元素和解析标签属性的区别

    解析元素时: Sting str = ele.elementText("name"); 而解析标签属性时: String key = ele.attributeValue(&quo ...

  7. java:Map借口及其子类HashMap五,identityHashMap子类

    java:Map借口及其子类HashMap五,identityHashMap子类 了解:identityHashMap子类 一般情况下,标准的Map,是不会有重复的key值得value的,相同的key ...

  8. 分享知识-快乐自己:springboot之thymeleaf (1):简单的thymeleaf例子

    之前搞springboot时,发现spring很推荐thymeleaf,所以看了看学了学,感觉不错,做个笔记先. 做个简单和例子,项目是springboot,所以引入themeleaf相关包 pom. ...

  9. poj 3666 Making the Grade(dp离散化)

    Making the Grade Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7068   Accepted: 3265 ...

  10. Android数据传递的五种方法汇总

    Android开发中,在不同模块(如Activity)间经常会有各种各样的数据需要相互传递,我把常用的几种 方法都收集到了一起.它们各有利弊,有各自的应用场景. 我现在把它们集中到一个例子中展示,在例 ...