注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

(转载)使用JNA简单调用DLL里的函数  

2015-07-16 16:08:24|  分类: Android |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

http://www.360doc.com/content/13/0826/21/11965070_310096284.shtml

使用JNA简单调用DLL里的函数 

1、在VC下创建一个动态链接库项目testJNA 

2、在头文件里声明函数 

C代码   

1. extern "C" _declspec(dllexport) int add(int first, int second);  

红色字体部分是必须的,包括定义结构体时也需要。应该是说此函数是发布的。 

3、在源码里实现函数 

C代码   

1. int add(int first, int second) {  

2.    printf("(c) test jna : %d + %d = %d", first, second, first + second);  

3.    return first + second;  

4. }  

4、生成dll文件 

5、定义一个表示链接库的接口 

接口TestJnaLib继承自com.sun.jna.Library,此接口有一个实例  

Java代码   

1. TestJnaLib INSTANCE = (TestJnaLib)Native.loadLibrary("testJNA.dll", TestJnaLib.class);  

此实例由jna通过反射自动生成。 

6、定义对应dll里的方法 

Java代码   

1. int add(int first, int second);  

7、调用本地方法 

Java代码   

1. TestJnaLib.INSTANCE.add(3, 5);  

Jna回调Java方法: 

1、在C语言部分定义带回调函数的函数 

C代码   

1. extern "C" _declspec(dllexport) void methodWithCallback(int (*fp)(int left, int right), int left, int right);  

红色加粗部分是函数指针。 

2、Java部分定义一个回调接口 

必须继承自com.sun.jna.Callback接口 

Java代码   

1. public interface FunCallBack extends Callback {  

2.    int invoke(int left, int right);  

3. }  

Invoke方法里的参数顺序与C函数的对应 

3、定义回调接口的实现 

Java代码   

1. public class CallbackFunImpl implements FunCallBack {  

2.    @Override  

3.    public int invoke(int left, int right) {  

4.        System.out.printf("in java :%d + %d = %d\n", left, right, left + right);  

5.        return left + right;  

6.    }  

7. }  

4、在表示链接库实现的接口里定义要回调的本地函数 

Java代码   

1. void methodWithCallback(Callback callback, int left, int right);  

本地函数的函数指针用Callback 接口替代。 

5、调用带函数指针的本地函数 

Java代码   

1. TestJnaLib.INSTANCE.methodWithCallback(new CallbackFunImpl(), 4, 6)  

JNA相关知识: 

使用JNA调用原生函数的模式: 

JNA不实用native关键字。 

JNI使用native关键字,使用一个个java方法来代表外部的原生函数。 

JNA使用一个java接口来代表一个动态链接库发布的所有函数。 

对于不需要的原生函数,可以不在java接口中声明java方法原型。 


使用JNI,需要使用System.loadLibrary方法,把专门为JNI编写的动态链接库载入进来,这个动态链接库实际上是真正需要的动态链接库的代理。 

使用JNA类库的Native类的loadLibrary方法,是直接把需要的动态链接库载入进来。使用JNA不需要编写作为代理的动态链接库,不需要编写一行原生代码。 

跨平台、跨语言调用原则: 

尽量使用基本、简单的数据类型; 

尽量少跨平台、跨语言传递数据! 

Java调用原生函数时,会把数据固定在内存中,这样原生函数才可以访问这些Java数据。这些数据,JVM的GC不能管理,会造成内存碎片。 

C语言的结构体是一个严格的规范,定义了内存的次序。因此,JNA中模拟的结构体的变量顺序绝对不能错。 

Java调用动态链接库中的C函数,实际上就是把一段内存作为函数的参数传递给C函数。动态链接库以为这个参数就是C语言传过来的参数。 

Structure类的write()方法会把结构体的所有字段固定住,是原生函数可以访问。 

JNI技术是双向的,既可以从Java代码中调用原生函数,也可以从原生函数中直接创建Java虚拟机,并调用Java代码。 

原生函数可以通过函数指针实现函数回调,调用外部函数来执行任务。这就是策略模式。 

Callback: 

任务回调定义必须继承自com.sun.jna.Callback接口,子类必须定义单个公有方法或一个名为callback的公有方法。必须持有到回调对象的一个存活引用。一个回调应该不抛出异常。 

com.sun.jna.Library: 

代表本地链接库的定义。可用如下形式定义: 

Java代码   

1. MyNativeLibrary INSTANCE = (MyNativeLibrary)Native.loadLibrary("mylib", MyNativeLibrary.class);  


虽然结构体和结构体字段的名字可以是任意的,但他们应该尽可能接近本地定义。参数名也一样。 

此接口支持在Java端多线程、并发调用本地方法。如果本地类库不是线程安全的,可用

Java代码   

1. Native.synchronizedLibrary(com.sun.jna.Library)  

来阻止多线程同时访问本地代码。 

链接库的搜索路径: 

jna.library.path 用户定义的路径; 

Jna.platform.library.path 平台定义的路径, 

com.sun.jna.Structure: 

代表本地结构体的对等Java类。 

当作为参数或返回值使用时,这个类被传递给struct * (指针);当作为另一个结构体的字段时,它被传递给struct (值传递)。 

标记接口Structure.ByReference和Structure.ByValue被用来提醒默认的行为。 

Structure属性传递给本地字段必须是public的。可以由下面可选的修饰符: 

volatile JNA不会修改字段,除非被要求,通过writeField(String); 

final   JNA会通过read()覆写字段,字段在java这边是不可变的。 

Structure属性的顺序与类型必须与本地结构体的字段一一对应。 

  评论这张
 
阅读(330)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017