java调用dll

<1> :****************************************************************************************************************

Java语言本身具有跨平台性,如果通过Java调用DLL的技术方便易用,使用Java开发前台界面可以更快速,也能带来跨平台性。

 

    Java调用C/C++写好的DLL库时,由于基本数据类型不同、使用字节序列可能有差异,所以在参数传递过程中容易出现问题。

 

    使用Java调用DLL动态链接库的方案通常有三种:JNI, Jawin, Jacob. 其中JNI(Java Native Interface)是Java语言本身提供的调用本地已编译的函数库的方法,本身具有跨平台性,可以在不同的机器上调用不同的本地库。Jawin和Jacob都是sourceforge.net的开源项目,都是基于JNI技术的依赖Windows的实现,使得在Windows平台下使用COM和DLL的更加方便。

 

    三、JNI

 

    sun相关文档:http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/jniTOC.html

 

    JNI的完整例子:http://www.pconline.com.cn/pcedu/empolder/gj/java/0506/642328.html

 

    JNI的应用方案是基于Java类和本地函数相映射的。其使用DLL的步骤还是相对比较麻烦,不但涉及到Java编程,还涉及到C/C++编程。

 

    JNI的使用步骤是:

 

    1.编写Java类,用该类将DLL对外提供的函数服务进行声明,其中的Java方法均声明为native,其方法签名可以自定义,不用实现函数体。

 

    2.用Javah工具将该Java类生成对应的.h头文件。

 

    3.最重要的比较麻烦的一步:编写C/C++代码实现.h头文件中声明的函数,该C/C++代码中包含jni.h头文件,并且编写代码时使用其中定义好的数据类型作为函数的输入和返回数据类型进行编程。用这种方法实现数据类型转换。例如数据类型:boolean(java) à jboolean(jni.h: typedef unsigned char jboolean),在自己编写的C/C++代码中使用数据类型jboolean映射Java中的boolean类型。在该步骤中,可以在C/C++代码中调用已经存在的DLL库。

 

    4.另外编写的Java代码时就可以使用该Java类了。

 

    在第3步中,编写C/C++函数时,可以使用一个叫interface pointer的env指针来调用JNI提供的一系列(很多)函数,用这些函数来访问JVM的对象和数据。

 

    使用JNI的缺点:使用比较麻烦,需要对已有的DLL进行封装,需要对C/C++比较了解。

 

    使用JNI的优点:可以跨平台调用本地库。

 

    四、Jawin

 

    官方网站:http://jawinproject.sourceforge.net/

 

    官方文档(Jawin介绍): http://jawinproject.sourceforge.net/jawin.html

 

    官方文档(Jawin使用DLL):http://jawinproject.sourceforge.net/jawinuserguide_dll.html

 

    官方文档(Jawin数据指令): http://jawinproject.sourceforge.net/instruction_docs.html

 

    Jawin的应用方案是基于函数调用时采用原始字节流传递数据的。就是在Java中指明一个DLL中的某个函数后,通过原始字节流(需要考虑参数数据类型所占的存储字节数及系统使用的字节序列)传递给该DLL函数需要的参数,其返回值也是通过原始字节流解析的方式获得正确的值。

 

    Jawin的使用步骤:

 

    1.环境配置:下载Jawin;Jawin.dll放入工程目录下;Jawin.jar相关jar文件加入到运行库中(LibPath或者Eclipse下配置工程的BuildPath-AddLibrary)。

 

    2.获得函数指针:new FuncPtr("DllFileName.DLL", "dllFunctionName");

 

    3.用LittleEndianOutputStream将函数需要的参数写入到一个原始字节流NakedByteStream。

 

    4.最重要的一步:调用FuncPtr.invoke()。传入参数比较复杂。

 

    5.解析上一步的返回值(字节数组)。

 

    第4步中传入的参数包括:

 

    1.指令字符串。一个"XXX:Y:ZZZ"格式的字符串。其含义分别是传入参数中的每个字节的数据类型意义、返回值的类型、需要从传入指针中读取的数据(inout类型参数)。比如:

 

    函数签名int func(int, int, struct s*, char*); //其中struct s*调用完函数后需要读出,struct s所占字节数为16。

 

    其指令字符串为:IIP16G:I:L4L4n16L4。该字符串在解析返回值(字节数组)时,首先应该是返回类型I对应的4个字节,然后是inout类型的参数中n16对应的16个字节。

 

    其中字符串的意义可以在Jawin提供的文件instructions.h中找到,或者在官方文档(Jawin数据指令)中找到常用的一些指令字符串的意义。

 

    2.传入参数的总字节大小。

 

    3.前面写好的传入参数的原始字节流。

 

    4.一个object数组。

 

    5.ReturnFlags,用以根据C/C++返回值将C/C++的错误转换为Java的异常并抛出。其中CHECK_NONE表示不检查;CHECK_FALSE和CHECK_WIN32分别表示返回0是FALSE和SUCCESS,根据是否出错决定是否抛出异常;CHECK_HRESULT表示使用COM模型中的HRESULT作为返回值,其错误码可以配置。

 

  使用Jawin的缺点:不方便调试,几乎所有的错误都抛出同样的异常COMException;需要对数据类型的转换比较了解;不能跨平台,对Windows的依赖性比较强。

 

    使用Jawin的优点:方便使用,不用进行C/C++开发,不用对原始DLL进行封装就可以方便使用。

 

 

 

    五 Jacob

 

    官方文档:http://danadler.com/jacob/

 

Jacob是Java-Com Bridge的缩写,也可以用来调用DLL。其底层也是使用JNI实现,也具有Windows 的平台依赖性,由于网上有人反映其易用性不如jawin,所以没有深入了解。

 

 

 

 

在java中使用Jawin组件访问Win

 

转自:

 

http://blog.sina.com.cn/u/5921d4ba010007jo

 

Author:Howwa@sina.com

日期:2007-2-23(正月初六)

环境:windowsXPHome版;Office2000;j2se1.6.0(JRE也是1.6.0);Jawin2.0-alpha1。

 

 

原由:使用Jacob访问windows下的COM组件的试验老是不成功(后来搜索到http://blog.sina.com.cn/u/435ce819010002r0,按他的办法据说可以成功),折腾了我一天。网上有说使用Jawin的,我试了一试就成功了,比Jacob顺利多了。据说Jawin比Jacob功能强大。

 

(1)Jawin(Java/Win32)是一个免费的、开放源代码的体系结构,用于Java组件与WindowsCOM对象或WindowsDLL之间的互操作。Jawin允许Java应用程序调用任何基于COM或DLL的遗留代码,而不需要编写任何JNI代码。您的代码将能与诸如MicrosoftOffice套件等可编写脚本的应用程序交互,调用诸如Microsoft的基于COM的XML解析器和工具等可编写脚本的逻辑组件,以及访问诸如Windows注册表、安全API和事件日志等Win32API特性。

(2)Jawin包括一个用于可编写脚本的COM组件的代码生成器(typebrowser),该代码生成器读取类型库,并自动产生Java应用程序中调用该组件所需要的Java存根(stub)。

 

http://sourceforge.net/projects/jawinproject/

 

Jawin2.0-alpha1下载地址:http://jawinproject.sourceforge.net/

 

下载文件是一个zip文件,叫jawin-2.0-alpha1.zip。解压缩后,将bin\jawin.dll文件(约264k)拷贝到系统的system32文件夹下,将lib\jawin.jar和lib\jawin-stubs.jar拷贝到C:\J2SE6\jre\lib\ext文件夹下(我的j2seJDK安装在c:\J2SE6文件夹下)。其他设置不需要做。

 

举例1:CreateWord.java,新建一个Word文档。

 

/******************************************

*CreateWord.java

*CreateaWorddocument

*

*version1.0

*authorHowwa@sina.com

http://blog.sina.com.cn/u/1495389370

*******************************************/

 

importorg.jawin.DispatchPtr;

importorg.jawin.win32.Ole32;

 

publicclassCreateWord{

publicstaticvoidmain(String[]args){

try{

Ole32.CoInitialize();

//初始化

DispatchPtrapp=newDispatchPtr("Word.Application");

//创建word对象

app.put("Visible",true);

//使word可见

DispatchPtrdocs=(DispatchPtr)app.get("Documents");

//获得document对象集合

DispatchPtrdoc=(DispatchPtr)docs.invoke("Add");

//新增一个文档

app.invoke("Activate");

//激活当前文档

Ole32.CoUninitialize();

//释放对象

}catch(Exceptione){

e.printStackTrace();

}

}

}

 

 

 

举例2:OpenWord.java,打开一个已存在的Word文档。

 

/******************************************

*OpenWord.java

*OpenaWorddocument

*

*version1.0

*authorHowwa@sina.com

http://blog.sina.com.cn/u/1495389370

*******************************************/

 

importorg.jawin.DispatchPtr;

importorg.jawin.win32.Ole32;

 

publicclassOpenWord{

publicstaticvoidmain(String[]args){

try{

Ole32.CoInitialize();

DispatchPtrapp=newDispatchPtr("Word.Application");

app.put("Visible",true);

DispatchPtrdocs=(DispatchPtr)app.get("Documents");

DispatchPtrdoc=(DispatchPtr)docs.invoke("Open","C:\\test.doc");

Ole32.CoUninitialize();

}catch(Exceptione){

e.printStackTrace();

}

}

}

 

在编译、运行时要注意大小写。同时,C盘根目录下要有test.doc文件。

/*

*CreateWordDoc.java

*

*1.Createanewworddocument;

*2.assignfontname

*3.assignfontsize

*4.writetwosentences

*5.saveit

*6.closeit

*7.exitword.

*

*@versionvision:1.0

*@authorhowwa@sina.com

*http://blog.sina.com.cn/u/1495389370

*/

 

importorg.jawin.DispatchPtr;

importorg.jawin.win32.Ole32;

 

publicclassCreateWordDoc{

publicstaticvoidmain(String[]args){

try{

Ole32.CoInitialize();

//初始化

DispatchPtrapp=newDispatchPtr("Word.Application");

//创建word对象

app.put("Visible",true);

//使word可见

DispatchPtrdocs=(DispatchPtr)app.get("Documents");

//取得document对象集合(Documents)

DispatchPtrdoc=(DispatchPtr)docs.invoke("Add");

//新增一个文档

app.invoke("Activate");

//激活当前文档

DispatchPtrobjTextFont=(DispatchPtr)((DispatchPtr)doc.get("Content")).get("Font");

//取得Font对象

objTextFont.put("Name","黑体");

//设置字体

objTextFont.put("Size","48");

//设置字号

DispatchPtrdocSelection=(DispatchPtr)app.get("Selection");

//取得Selection对象

docSelection.invoke("TypeText","Jawwintesttext!\nJawin测试文本。");

//使用TypeText方法添加文本

doc.invoke("SaveAs","c:\\jawintest.doc");

//保存文档(保存在C盘根目录下)

//doc.invoke("Close");

//关闭当前文档,去掉前面的注释符并重新编译后可生效

//app.invoke("Quit");

//退出Word,去掉前面的注释符并重新编译后可生效

Ole32.CoUninitialize();//释放对象

}catch(Exceptione){

e.printStackTrace();

}

}

}

<2> ************************************************************************************************************************
资料来源于:

http://pettypig.bokee.com/4657931.html

http://www.examda.com/ncre2/JAVA/fudao/20080118/114013654.html

http://hi.baidu.com/psq125584192/blog/item/091526adbced9c0a4b36d683.html


  1. 用java写一个类,该类中用native关键字声明一个方法,该方法可带可不带参数。
    public class Sec {
    //这句用native声明该方法为外部方法,即连接库中的方法。
    public native void displayHelloWorld(String name);
    //这段代码块在类被加载后首先执行,读取连接库Sec,不用带后缀,是dll还是so由系统自动判断。
    static {
       System.loadLibrary("Sec");
    }
       public static void main(String[] args){
       new Sec().displayHelloWorld(args[0]);
    }
    }
  2. 用命令javac Sec.java编译该类,产生Sec.class。
  3. 用命令javah Sec产生Sec.h文件,该文件用来被C/C++程序调用来生成所需的库文件,此处即dll文件。查看会发现文件内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Sec */

#ifndef _Included_Sec
#define _Included_Sec
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:     Sec
* Method:    displayHelloWorld
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_Sec_displayHelloWorld
(JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

其中的JNIEXPORT void JNICALL Java_Sec_displayHelloWorld (JNIEnv *, jobject, jstring) 是我们所关心的。JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。

   4.     用visual c++ 6.0 或者其他工具建立new -> project ->Win32 Dynamic-Link Library -> An empty Dll project,然后在FileView视图中在Header Files下导入刚才生成的Sec.h文件,在Source Files 下建立Sec.cpp文件,代码如下:

#include <iostream>
#include "Sec.h"
using namespace std;

JNIEXPORT void JNICALL Java_Sec_displayHelloWorld(JNIEnv *env, jobject, jstring jstr)
{
//以下代码来自互联网
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0)
{
   rtn = (char*)malloc(alen + 1);
   memcpy(rtn, ba, alen);
   rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
//截止

cout<<"HelloWorld,My name is "<<rtn<<endl;
}

代码中方法的名称以及声明就是来源于Sec.h文件。只是由于要用到参数,因此在函数声明中的参数部分指定了参数名称。而在Sec.h中,仅仅指定了函数参数类型。其中参数类型比如jstring 是JNI为中介使JAVA的String类型与本地的char *沟通的一种类型,需要进行处理才能与本地语言(c/c++)进行编码的转换和沟通。转换的代码为“//以下代码来自互联网”和“//截止”之间的部分,这部分尚需认真学习钻研。还有许多其他的类型也需要转换。

    5.   为了确保编译通过,应当让编译器将java JDK目录下include文件夹以及子文件夹下的*.h文件包含进去,或者复制他们到...\Microsoft Visual Studio\VC98\Include目录下。最后编译生成Sec.dll文件。

    6.   将Sec.dll文件和Sec.class文件放在同一个目录下,执行java Sec lanvis,则会看到输出:

HelloWorld,My name is lanvis

表示运行成功。

 

通常的情况是,我们并不知道链接库的源代码,也没有修改链接库的权限。这样为了调用链接库,我们可以再写一个自己的链接库,再在自己的这个链接库中调用目标链接库。一个dll A调用另一个dll B只需要在A中正常调用B中的方法,然后在编译的时候指定B链接库就可以了(cl命令中指定或者在编译器中指定)。

PS:以上成功利用java调用了一个链接库,下一步我要演示的是让java从注册表中获得一个链接库的注册信息,然后进行调用。

 

<3>****************************************************************************************************************

Jawin(Java/Win32)是一个免费的、开放源代码的体系结构,用于 Java 组件和通过 Windows COM 对象或 Windows DLL 来公开的组件之间的互操作。Jawin 允许 Java 应用程序调用任何基于 COM 或 DLL 的遗留代码,而不需要编写任何 JNI 代码。您的代码将能与诸如 Microsoft Office 套件等可编写脚本的应用程序交互,调用诸如 Microsoft 的基于 COM 的 XML 解析器和工具等可编写脚本的逻辑组件,以及访问诸如 Windows 注册表、安全 API 和事件日志等 Win32 API 特性。Jawin 包括一个用于可编写脚本的 COM 组件的代码生成器。该代码生成器读取类型库,并自动产生从 Java 应用程序调用该组件所需要的Java存根(stub)。

 
使用方法:
解压后,将bin/jawin.dll拷贝到System32目录下,然后将lib/jawin.jar和lib/jawin-stubs.jar拷贝到jdk的lib/ext目录下
 
好现在就可以运行其自带的demo了~
/*
* HelloDll.java -
*
* This file is part of the Jawin Project: http://jawinproject.sourceforge.net/
*
* Please consult the LICENSE file in the project root directory,
* or at the project site before using this software.
*/
/* $Id: HelloDll.java,v 1.3 2004/06/14 20:16:38 arosii_moa Exp $ */
package demos;
import org.jawin.COMException;
import org.jawin.FuncPtr;
import org.jawin.ReturnFlags;
/**
* Demo that uses the Win32 MessageBoxW API-method.
*
* @version     $Revision: 1.3 $
* @author      Stuart Halloway, http://www.relevancellc.com/halloway/weblog/
*/
public class HelloDll {
public static void main(String[] args) throws Exception {
   FuncPtr msgBox = null;
   try {
    msgBox = new FuncPtr("USER32.DLL", "MessageBoxW");
    msgBox.invoke_I(0, "Hello From a DLL", "From Jawin", 0, ReturnFlags.CHECK_FALSE);
   } catch (COMException e) {
    // handle exception
    e.printStackTrace();
    throw e;
   } finally {
    if (msgBox != null) {
     try {
      msgBox.close();
     } catch (COMException e) {
      // handle fatal exception
      e.printStackTrace();
      throw e;
     }
    }
   }
}
}
注意运行是 要加demos.HelloDll

转载于:https://www.cnblogs.com/MMLoveMeMM/articles/3171258.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值