浅谈JAVA通过JNI调用本地的DLL

        首先了解下,什么是JNI, JNI是Java Native Interface的缩写。从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。 
        使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少保证本地代码能工作在任何Java 虚拟机实现下。 
        说白了就是让JAVA和其他语言开的东西进行交互,这里通过一个实例着重介绍下,如何通过JNI使JAVA可以调用本地的DLL。
        实例描述:假定现在有一个现成的DLL文件,(这种情况在项目开发中很容易遇到,比如说客户方原来有个老系统,是用C/C++等来开发的,一堆写好的DLL,而如果在功能需求方面没有变化的提前下,利用这些DLL能给项目省下不少工夫),DLL的源文件已经找不到了,通过dump查看只有一个sayHello方法,输入一个名字,如Tom,输出Hello Tom!(当然为了实现这个例子,这个DLL还是要先写出来,但现实中,这个DLL往往是现成了,无需改变,也没法改变)。目前的需求是这样的,在JAVA程序实现:输入一个Tom,调用这个DLL,输出Hello  Tom!
        实现思路:众所周知,JAVA是不能直接调用DLL文件,不过可以通过JNI,生成一个四不像的DLL,这个DLL既能用JAVA语法,又能与C/C++开发出来的DLL进行交互。于是我们可以通过JAVA调用这个四不像的DLL1,然后在这个DLL1中调用现成的DLL2,实现整个过程,如下图:
       
        具体实现:
        1。写一个简单的C++程序,生成那个现成的DLL2,名为c_dll.cpp,实现sayHello这个方法,代码如下:
      
#include  < objbase.h >

#include 
< iostream.h >

extern   " C "  __declspec(dllexport)  void  sayHello ( char   *  name)

{

    cout
<<"Hello "<<name<<endl;

}


BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, 
void *  lpReserved) 

{

    HANDLE g_hModule;

    
switch(dwReason)

    
{

    
case DLL_PROCESS_ATTACH:

       g_hModule 
= (HINSTANCE)hModule;

       
break;

    
case DLL_PROCESS_DETACH:

        g_hModule
=NULL;

        
break;

    }


    
return TRUE;

}
       通过命令或IDE将其编译成DLL文件,如命令提示符下:
cl  / c c_dll.cpp
link 
/ dll c_dll.obj
                                                                                
       生成dll文件c_dll.dll。
      2。写一个简单的java类,声明一个由native修饰的方法sayHello(),代码如下:
           
public   class  j_dll  {

    
public native void sayHello(String name);

    
public static void main(String[] args) {
        
// TODO Auto-generated method stub
    }

}
          这里native修饰的sayHello方法就是java调用本地dll的程序入口。
      3。通过JNI将这个java类编译成充当桥梁作用的DLL1,具体步骤如下:
            1)先用命令生成头文件j_dll.h,命令提示符下进入java类的目录,执行:
           
javac j_dll.java
javah j_dll
                 就会生成一个名为j_dll.h的头文件,这个文件对于生成DLL1来说是必需的。j_dll.h如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
< jni.h >
/* Header for class j_dll */

#ifndef _Included_j_dll
#define  _Included_j_dll
#ifdef __cplusplus
extern   " C "   {
#endif
/*
 * Class:     j_dll
 * Method:    sayHello
 * Signature: (Ljava/lang/String;)V
 
*/

JNIEXPORT 
void JNICALL Java_j_1dll_sayHello
  (JNIEnv 
*, jobject, jstring);

#ifdef __cplusplus
}

#endif
#endif
                这个文件是自动生成的,无需修改!这里的JNIEXPORT void JNICALL Java_j_1dll_sayHello
  (JNIEnv *, jobject, jstring);方法就是按照java类中的sayHello方法生成的。
           2)生成DLL1,新建一个名为j_dll.cpp的文件,代码如下:
#include  " stdio.h "
#include 
" j_dll.h "  
#include 
< windows.h >
#include 
< iostream.h >  


// 加载dll 
HINSTANCE hinst  =  NULL;

JNIEXPORT 
void  JNICALL Java_j_1dll_sayHello(JNIEnv  * env, jobject obj, jstring s)
{
    
//定义一个函数指针
    typedef void (* sayHello )(char * name);
    
//定义一个函数指针变量
    sayHello sh = NULL;  

    
if (NULL == hinst)
    
{
        hinst
=::LoadLibrary("c_dll.dll");
    }
    
    
//找到dll的sayHello函数                           
    sh =(sayHello)GetProcAddress(hinst, "sayHello");  
    
//调用dll里的函数
    try{
    
if (NULL != sh)
    
{
        
char *str;
        str 
= (char *)env->GetStringUTFChars(s,0);
        (
*sh)(str); 
        env
->ReleaseStringUTFChars(s,str);
    }

    FreeLibrary(hinst); 
    }
catch(...){
        cout
<<"exception"<<endl;
    }

}
              注意开始要引入进来j_dll.h文件,关键代码有写注释,然后按照生成DLL2的方法生成DLL1,名为j_dll.dll(具体方法略)。
      4。补全j_dll.java的代码,如下:
public   class  j_dll  {
    
// Java调用dll
    static {
        
try {
            System.loadLibrary(
"j_dll");
        }
 catch (Error e) {
            System.exit(
0);
        }

    }

    
public native void sayHello(String name);

    
public static void main(String[] args) {
        
// TODO Auto-generated method stub
        j_dll jd = new j_dll();
        jd.sayHello(
"TOM");
    }

}

        编译java类,运行之,输出Hello Tom。

        这样,整个JAVA调用中间层DLL,中间层DLL调用现成的DLL就完成了,是不是很简单呢?希望喜欢JAVA的朋友一起交流哦!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值