近日项目中需要用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. Netty使用LineBasedFrameDecoder解决TCP粘包/拆包

    TCP粘包/拆包 TCP是个”流”协议,所谓流,就是没有界限的一串数据.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TC ...

  2. HDU 4417 Super Mario(2012杭州网络赛 H 离线线段树)

    突然想到的节约时间的方法,感觉6翻了  给你n个数字,接着m个询问.每次问你一段区间内不大于某个数字(不一定是给你的数字)的个数 直接线段树没法做,因为每次给你的数字不一样,父节点无法统计.但是离线一 ...

  3. Codeforces 914C Travelling Salesman and Special Numbers:数位dp

    题目链接:http://codeforces.com/problemset/problem/914/C 题意: 对数字x进行一次操作,可以将数字x变为x在二进制下1的个数. 显然,一个正整数在进行了若 ...

  4. 计算地球上两个坐标点(经度,纬度)之间距离sql函数

    go --计算地球上两个坐标点(经度,纬度)之间距离sql函数 --作者:lordbaby --整理:www.aspbc.com CREATE FUNCTION [dbo].[fnGetDistanc ...

  5. 代码题(14)— 合并有序链表、数组、合并K个排序链表

    1.21. 合并两个有序链表 将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两个链表的所有节点组成的. 示例: 输入:1->2->4, 1->3->4 输出 ...

  6. POJ 2309 BST(二叉搜索树)

    思路:除以2^k,找到商为奇数的位置,k为层数,有2^(k+1)-1个节点 这里直接用位运算,x & -x 就求出 2^k 了. #include<iostream> using ...

  7. Android studio导入第三方类库源码以及jar包

    新建一个Android项目,项目结构如下: 1.添加第三方类库源码 首先将第三方类库考入与app同级的目录下: 之后,在build.gradle(Moudule:app)下添加编译代码:在seting ...

  8. 关于C++多态的理解

    多态,即多种形态.对于具有继承关系的一类对象,子类表现出了父类的某些特性,但是表现的不一样,这就是多态的现实体现.例如动物可以发声,但是狗是旺旺,狗是动物的一种,但是表现了不同的叫的特点,这就是多态. ...

  9. Android数据存储的五种方法汇总

    本文介绍Android中的5种数据存储方式. 数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是: 1 使用SharedPreferences存储数据 2 ...

  10. freeMarker(十一)——模板语言之指令

    学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net 1.assign 概要 <#assign name1=value ...