Java动态库调用

来源:互联网 发布:淘宝智能旺铺又什么用 编辑:程序博客网 时间:2024/06/07 10:04

1. 方法简介

      a). JNI调用动态库: JNI是安装JDK的时候自带的内容,适用场景为开发前就知道动态库需要供Java程序调用,且需要Java程序提供动态库开发的头文件内容。使用相对复杂,且如果是对于已经存在的动态库需要开发中间库来适配
 b). Jacob 调用动态库:Jacob是SUN提供的一个用于调用动态库的类库,使用相对简单,不需要二次开发,但是需要手动进行一些配置工作
 c). JNA 调用动态库:JNA是对JNI的二次封装,使用简单,不需要进行二次开发,同样不需要手动进行配置,导入jar包就可以工作

2. JNI调用动态库

假设已经存在一个动态库add.dll,里面存在一个函数int add(int a,int b);现在需要通过JNI去调用这个方法。
 ·=> 编写调用中间动态库myAdd.dll的类TestDll.java
 ·=> 通过命令javah得到中间动态库的头文件TestDll.h
 ·=> 编写生成中间动态库myAdd.dll
 ·=> 将生成的myAdd.dll放到TestDll.class同目录下,运行java TestDll查看结果

2.1编写调用中间动态库的类生成TestDll.h

【TestDll.java】

public class TestDll {private native static int add(int a, int b);static {System.loadLibrary("myAdd"); // 该动态库名称为中间动态库,由java程序使用,负责调用需要使用的动态库。}/** * @param args */public static void main(String[] args) {System.out.println(add(4, 5));}}



进入cmd执行javac TestDll;javah TestDll


 
【TestDll.h】

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class TestDll */#ifndef _Included_TestDll#define _Included_TestDll#ifdef __cplusplusextern "C" {#endif/* * Class:     TestDll * Method:    add * Signature: (II)I */JNIEXPORT jint JNICALL Java_TestDll_add  (JNIEnv *, jclass, jint, jint);#ifdef __cplusplus}#endif#endif

2.2 编写中间动态库myAdd.dll

使用vc工具先生成win32 Dynamic-Link Library空工程,将上面生成的头文件TestDll.h添加进去,同时还需要添加jdk下include目录中 的jni.h、jni_md.h这两个头文件,最好将jni.h文件放入安装目录下include的目录下,添加调用需要使用的动态库的实现文件TestDll.cpp
【TestDll.cpp】

//TestDll.cpp#include <windows.h>#include "TestDll.h"typedef int (*padd)(int,int);JNIEXPORT jint JNICALL Java_TestDll_add  (JNIEnv *, jclass, jint x, jint y){ HINSTANCE hins = ::LoadLibrary("add.dll"); if(hins == NULL) {  return 0; } int res; padd pa = (padd)GetProcAddress(hins,"add"); if(pa != NULL) {  res = pa(x,y); } ::FreeLibrary(hins); return res;}


编译生成myAdd.dll,将myAdd.dll和add.dll放到TestDll.class同目录下,运行java TestDll查看结果为: 9
至此JNI调用动态库完成~

3. Jacob 调用动态库

3.1 Jacob开发环境配置

下载jacob需要的库 Jacob.zip
解压后将jacob.jar复制到项目中,或者将其加入到ClassPath中。将jacob-1.18-x86.dll放入到jdk的bin目录中

3.2 注册动态库获取ClassID以及ProgID

设动态库名称为mydll.dll 
    => 编写windows批处理文件regMyDll.bat,记事本打开编辑regsvr32 mydll.dll双击执行,在win8下可能要右键以管理员身份运行
    =>Win + R输入regedit打开注册表,编辑->查找mydll.dll,得到ClassID: 135CB56E-FDB4-43B6-A386-CD0C15295C07;ProgID: WebScan.WScan.1 (一般我们只取ProgID 即可)


 3.3 编写调用动态库的类


创建ActiveX控件对象,由于classid每次注册可能会不一样,所以取ProgID作为ActiveXComponent初始化的入参
【TestJcob.java】

public class TestJcob { private static ActiveXComponent activeX;//ActiveX控件对象 private static Dispatch dispath;//MS级别的调度对象 static {  //创建ActiveX控件对象  //activeX = new ActiveXComponent("CLSID:135CB56E-FDB4-43B6-A386-CD0C15295C07");  activeX = new ActiveXComponent("WebScan.WScan.1");  //获得调度对象  dispath = activeX.getObject(); } public static int add(int a,int b){  Variant ret = Dispatch.call(dispath, "add",a,b);     return ret.getInt(); } /**  * @param args  */ public static void main(String[] args) {  System.out.println(add(4,5)); }}

3.4 读取未知dll的函数接口(感兴趣的可以研究下)

将未知dll或者ocx或其他注册,使用VS提供的C:\Program Files\Windows Kits\8.0\bin\x86工具oleview.exe来查看dll的内部变量定义以及函数结构
使用方法:打开工具File->View TypeLib选择未知dll查看

4. JNA 调用动态库

下载jna.jar文件,复制并依赖到项目中
设调用的动态库名字为Add.dll内部函数为int add(int a,int b);
【TestJNA.java】

public class TestJNA { public interface Add extends StdCallLibrary {  Add instance = (Add) Native.loadLibrary(System.getProperty("user.dir") + "\\Add.dll", Add.class);  int add(int a,int b); } public static int add(int a,int b){  return Add.instance.add(a, b); }  public static void main(String[] args) {  System.out.println(add(4,5)); }}



0 0