摘 要:随着计算机普及率的提升以及软件行业的飞速发展,计算机语言也越来越受到广大计算机爱好者和计算机软件开发人员的关注。同时越来越多的服务要求跨平台的实现。当前比较流行的两大语言VC++和Java几乎可以开发所有基于B/S架构和基于C/S架构的软件项目。它们各有所长,如果能将Java和VC有效地结合起来,实现二者的互相调用,那将可以取长补短,同时可以避免许多重复的工作,提高编程的效率。
关键词:Java; VC;DLL;MFC; 汉字编码
虽然Java和VC++是当前两大主流的编程语言,但是如果两者之间不能有效结合,实现相互调用的话,势必会给编程人员的工作带来诸多不便,增加许多的重复工作,甚至有可能造成整个项目的搁浅。另外,不同语言之间的互相调用还可以有效地利用现有程序,并且不需要一遍一遍地撰写类似的程序代码。为此,本文引人了VC++中的动态链接库文件,通过实例阐述了如何在Java中成功调用VC++动态链接库的问题[1]。
1 技术介绍
1.1 动态链接库DLL
动态链接库DLL好比一个封装起来的“仓库”,DLL是Dynamic Link Library的缩写,其中封装了一些或者部分可以被共享的例程和资源,采用动态的连接方式就能够被其他程序动态装载、运行以完成某些特定的功能。
采用动态链接库进行软件开发,具体优势主要有下面几点:
(1)对硬件资源方面的要求比较小
在程序开发过程中,经常遇到多个程序调用同一个函数库的情况,这时如果使用动态链接库,就可以大大减少在磁盘和物理内存中重复代码的加载。只有当生成的EXE 文件确实要调用该DLL模块时,系统才会将其加载到内存空间中去。
(2)项目体系结构模块化开发
程序结构模块化对项目开发有着重要的作用,能够方便项目的管理与功能的定制。动态链接库的设计包含这种思想。另外,动态链接库支持多语言。这样可以有更广阔的应用平台,方便开发程序的移植,也可以在不同的开发平台上调用。通常当开发的系统为庞大系统,避免不了有许多重复类型的功能,这时如果将这些类似的功能单独做成DLL,将可以大大减少开发的工作量和提高开发的速度[2]。
(3)软件维护方便
当动态链接库中的函数需要更新或修复时,采用动态链接库更方便。因为部署及安装动态链接库在此就不要求重新建立程序与该DLL 的连接。此外,如果多个程序使用同一个DLL,则多个程序都将从该更新或修复中获益。当使用定期更新或修复的第三方DLL 时,此问题可能会更频繁地出现,升级到DLL 就可以更容易解决这些问题。
(4)功能实现的细节隐藏
考虑到一些重要技术的保密和知识产权的保护,在某些情况下,通常将项目中一些功能实现的具体细节隐藏起来,即希望里面的部分代码不被公开,这时动态链接库就是一项非常不错的实现方法。动态链接库可以被其他应用程序访问调用,但将代码的具体细节完全隐藏起来。另外,DLL的语言无关性也是很重要的一个方面。正是由于动态链接库DLL与语言无关的这个特点,故用VC++创建的DLL可以被其他任何支持动态链接库的编程语言调用, 比如VB、Delphi、PD[3]等。
1.2 Java本地编程接口JNI
JNI(Java Native Interfacejava)其实就是指Java本地程序接口,属于JDK中的一部分。当Java程序中有需要调用通过VC++语言编写的DLL时,此时最佳选择就是使用JNI技术。通过使用Java本地接口书写程序,可以确保代码在不同的开发平台上方便移植。JNI使得运行于Java虚拟机的代码可以操作用C、C++或者汇编等书写的应用程序或库,同时也可以通过调用相应的接口函数将Java虚拟机内嵌到本地应用程序中。
特别需要提醒的是,只要有下面几种情况中的任何一种出现时,程序员就需要利用JNI来进行处理:(1)所开发的应用程序要使用到与平台相关的属性, 但Java标准类库不支持对这些属性的处理; (2)已经拥有了利用其他编程语言实现的应用程序或库,希望用Java 直接调用这些应用程序或库来实现; (3)程序中的某个模块对运行的时间效率要求很高,此时希望用比较低级的语言(如汇编)来实现,同时希望在Java应用程序中使用这个模块[4]。
2 设计与实现
2.1 设计步骤
使用JNI在Java中调用VC++写的DLL有以下几个步骤:(1)创建Java类;(2)编译Java代码并生成头文件;(3)开发DLL并实现方法;(4)编译动态链接库;(5)测试运行程序。
2.2 设计实例
2.2.1 无包情况
(1)在Java中写调用VC的代码,具体如下:
public class JieCheng{
static{
System.loadLibrary("JieCheng");
//注意:不写扩展名,名字要与DLL的文件名一致
}
public native static int jiecheng(int n); //声明native方法
public static void main(String args[]){
int s;
JieCheng jc=new JieCheng();
s=jc.jiecheng(5);
System.out.println(s); //声明main法
}
}
(2)在运行弹出的输入框中输入cmd进入dos界面,通过cd命令进入到安装Java的路径下面的bin中,假设安装目录是D:\Program Files\Java\jdk1.6.0_10\bin,把JieCheng.java文件移到D:\Program Files\Java\jdk1.6.0_10
\bin目录下,输入javac JieCheng.java,可以看到在该目录下生成了JieCheng.class的文件。输入javah JieCheng生成了JieCheng.h文件。具体如下:
#include
/* Header for class JieCheng */
#ifndef _Included_JieCheng
#define _Included_JieCheng
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: JieCheng
* Method: jiecheng
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_JieCheng_jiecheng
(JNIEnv *, jclass, jint);
#ifdef __cplusplus
}
#endif
#endif
(3)在VC下创建DLL文件,名字一定要是System.loadLibrary("JieCheng")中的JieCheng,把JieCheng.h文件直接复制到该VC文件下,同时把jni.h,jni_md.h复制到VC工程下。在JieCheng.cpp文件下实现在Java中声明过的方法,注意方法名一定要与JieCheng.h中声明的方法一致,在方法中写入代码如下:
#include"JieCheng.h"
JNIEXPORT jint JNICALL Java_JieCheng_jiecheng(JNIEnv *, jclass, jint n)
{
int i,s;
s=1;
for(i=1;i<=n;i++){
s=s*i;}
return s;
}
(4)在VC下编译生成JieCheng.dll文件,把该文件直接复制到Java的安装目录下面的bin目录下:D:\Program Files\Java\jdk1.6.0_10\bin。
(5)把在VC下编译生成的JieCheng.dll文件直接复制到Java的安装目录的bin目录下:D:\Program Files\Java\jdk1.6.0_10\bin。运行命令:java JieCheng,本例中,JieCheng函数用于求一个数的阶乘,所以在屏幕上显示的结果是“120”。
2.2.2 有包情况
有包的情况与上面介绍的无包情况大致相同。但需要特别强调、引起注意的地方是:首先需要在Java的安装目录bin下创建包名文件夹,假设创建的包名文件夹的名称为NegerVector,然后把.java文件放在此文件夹中。接下来就是进入DOS环境下运行两个命令,首先运行:javac NegerVector\ JieCheng.java;然后运行:javah Neger Vector.JieCheng。其他的可以参照无包情况了,因为接下来与无包的情况基本相同。
在许多大型项目的开发过程中,从提高开发效率以及实现代码重用的角度来看,跨平台服务的开发是未来的发展趋势,从而经常需要在Java程序中调用VC中的DLL。本文从JNI技术出发,通过简单的实例详细阐述了JNI调用VC++写的DLL的程序,解决了Java与VC的有效结合,实现了它们之间的相互调用。
参考文献
[1] 王志文,夏秦,李平均.Java程序设计(修订本)[M].西安:西安交通大学出版社,2005.
[2] 孙文华.一种基于Java编程的脏字过滤器的设计[J].微型机与应用,2012,31(9):18-19,23.
[3] 王敏,邵定宏,陆金桂.动态链接库技术及其应用实[J].微计算机信息,2006,22(27):272-274.
[4] 宋晓字,王永会. Visual C++高级编程技术与实例[M].北京:中国水利水电出版社,2006.