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

韬光养晦

路漫漫其修远兮,吾将上下而求索

 
 
 

日志

 
 

java调用dll  

2008-06-13 13:26:26|  分类: JAVA |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

因为上PhD. Yang的课,他让我做个演示来演示中间件的原理,我就想到了用java的JNI机制来调用一个dll进行演示。参考资料来源于:

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从注册表中获得一个链接库的注册信息,然后进行调用。这个才是PhD. Yang的要求。

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

历史上的今天

评论

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

页脚

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