Chinaunix首页 | 论坛 | 博客
  • 博客访问: 64022
  • 博文数量: 18
  • 博客积分: 1430
  • 博客等级: 上尉
  • 技术积分: 172
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-06 00:29
个人简介

随心 随性 专注一心

文章分类

全部博文(18)

文章存档

2015年(2)

2014年(9)

2013年(3)

2011年(1)

2010年(3)

我的朋友

分类: Java

2011-05-06 14:02:09

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相关文档:

 

    JNI的完整例子:

 

    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

 

    官方网站:

 

    官方文档(Jawin介绍): jawin.html

 

    官方文档(Jawin使用DLL):jawinuserguide_dll.html

 

    官方文档(Jawin数据指令): 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

 

    官方文档:

 

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)。

 

 

Jawin2.0-alpha1下载地址:

 

下载文件是一个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文档。

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文档。

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文件。

 

 

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();

}

}

}

阅读(607) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~