java 调用第三方dll学习心得

来源:互联网 发布:中国好声音网络歌手 编辑:程序博客网 时间:2024/04/25 14:23

1.   用java编写一个类,类中使用System.LoadLibrary方法调用动态链接库,同时声明动态链接库中个各个方法。

2.   然后用javac编译成class文件,再用javah生成.h文件。

3.   编写一个C/C++程序,生成java可以直接调用的DLL文件。

4.   把生成的DLL文件何java文件放在一块,重新运行开始写的java程序。

但是问题是很多C中使用的数据类型在java中不能使用,如unsigned char *,HANDLE等,如何转换呢?我觉得这是很常用的啊,怎么很少有人回答这种问题呢?也许是我的搜索能力太差了吧,呵呵!

通过几天的努力我终于把问题解决了,我把在编写过程中遇到的一写问题列出来,虽然我的程序有点简单,想跟大家分享一下,希望与我一样困惑的朋友能够用得上。

1.   在JAVA程序中,首先声明java要调用的库名称,库的扩展名字可以不用写出来,该库名称不是商家提供的库,名字可以随便去,最好不要和商家提供的库名称一样,否则会出错。还需要对将要调用的方法做本地声明,使用关键字native,只需声明不要具体实现,方法名和参数不需要和商家提供的库中方法一样,况且一些C参数类型也没办法使用java语言表示。例如我的程序SmartCard.java内容如下:

public class SmartCard{

static{

System.loadLibrary("SmartCard");//后面使用C/C++编写的JAVA能直接调用的库

}

//java中需要用到的本地方法声明,从安全上考虑最好把它设成私有

private native int iniCom(int ComPort,int BaudRate);

private native int closeCom(int ComPort);

private native String readPersonalInfo(int ComPort);

//外部类能调用的方法

public int iniComTemp(int ComPort,int BaudRate){

return this.iniCom(ComPort,BaudRate);

}

public int closeComTemp(int ComPort){

return this.closeCom(ComPort);

}

public String readPersonalInfoTemp(int ComPort){

return this.readPersonalInfo(ComPort);

}

}

2.   使用javac SmartCard编译生成CLASS文件,再调用javah SmartCard生成C/C++的头文件

比如我的程序生成的.h文件内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class SmartCard */

#ifndef _Included_SmartCard

#define _Included_SmartCard

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class:     SmartCard

* Method:    iniCom

* Signature: (II)I

*/

JNIEXPORT jint JNICALL Java_SmartCard_iniCom

(JNIEnv *, jobject, jint, jint);

/*

* Class:     SmartCard

* Method:    closeCom

* Signature: (I)I

*/

JNIEXPORT jint JNICALL Java_SmartCard_closeCom

(JNIEnv *, jobject, jint);

/*

* Class:     SmartCard

* Method:    readPersonalInfo

* Signature: (I)Ljava/lang/String;

*/

JNIEXPORT jstring JNICALL Java_SmartCard_readPersonalInfo

(JNIEnv *, jobject, jint);

#ifdef __cplusplus

}

#endif

#endif

3.   C/C++中所需做的工作,对于已生成的.h文件,C/C++所需要做的就是把它的各个方法具体实现,然后连接成库文件即可,在方法实现过程中需要用到商家提供的第三方DLL文件,以及转化数据类型。编写是需要把刚才生成的.h文件添加到头文件,另外还要把jdk中include文件夹下的jni.h以及include/ win32下的jni_md.h添加到编译器中的include中,或者何源文件放在一起,又是会提示jnih找不到,这是你可以把使用javah生成的.h文件中的<jni.h>改成“jni.h”。类型转换及如何调用商家提供的库可分析一下代码,要注意的是这里使用的DLL文件不能与开始java中使用的DLL文件同名。

#include "stdafx.h"

#include "windows.h"

#include "string.h"

#include "SmartCard.h"//该头文件须被包含进来

typedef int (_stdcall *INICOM)(int ComPort,int BaudRate);//参数需要何商家提供的DLL文件中方法的参数一致

typedef int (_stdcall *CLOSECOM)(int ComPort);

typedef int (_stdcall *IDREAD)(int ComPort,unsigned char *Name,unsigned char *buffer);

HINSTANCE dllHandle;

int result;

//初始化串口方法实现

JNIEXPORT jint JNICALL Java_SmartCard_iniCom(JNIEnv *env, jobject jo, jint ComPort, jint BaudRate){

INICOM pIniCom;

dllHandle = LoadLibrary("SmartCom411SFJ.dll");//商家提供的库文件

pIniCom = (INICOM)GetProcAddress(dllHandle,"IniCom");//寻找商家提供库中对应的方法名

result = pIniCom(ComPort,BaudRate);

FreeLibrary(dllHandle);

return result;

}

//关闭串口方法实现

JNIEXPORT jint JNICALL Java_SmartCard_closeCom(JNIEnv *env, jobject jo, jint ComPort){

CLOSECOM pCloseCom;

dllHandle = LoadLibrary("SmartCom411SFJ.dll");

pCloseCom = (CLOSECOM)GetProcAddress(dllHandle,"CloseCom");

result = pCloseCom(ComPort);

FreeLibrary(dllHandle);

return result;

}

JNIEXPORT jstring JNICALL Java_SmartCard_readPersonalInfo(JNIEnv *env, jobject jo, jint ComPort){

IDREAD pIdRead;

unsigned char name[8]="",*na=name;

unsigned char buffer[20]="put card on it",*buf=buffer;

char splitLetter[]="|";

jstring jstr;

dllHandle = LoadLibrary("SmartCom411SFJ.dll");

pIdRead = (IDREAD)GetProcAddress(dllHandle,"ReadPersonalInfo");

result = pIdRead(ComPort,name,buffer);

char resultStr[29]="",*reTemp=resultStr;

if(result==0){

for(int i=0;i<8;i++){

*(reTemp+i)=*(na+i);

}

*(reTemp+8)=splitLetter[0];

for(i=9;i<29;i++){

*(reTemp+i)=*(buf+i);

}

jstr=env->NewStringUTF(resultStr);//返回用namebuffer中的信息,中间用”|”分割开

}else if(result==-6){

jstr=env->NewStringUTF("-6");

}else if(result==1){

jstr=env->NewStringUTF("1");

}else if(result==16){

jstr=env->NewStringUTF("16");

}else{

jstr=env->NewStringUTF("-2");

}

FreeLibrary(dllHandle);

return jstr;

}

4.   编译生成库文件,生成的库文件名需和第一步中的库名一致。在需要使用商家提供的库中方法的java类中调用第一步中声明的对应方法即可。我编写的一个测试类如下:

public class test{

public static void main(String[] args){

SmartCard sc = new SmartCard();

int i = sc.iniComTemp(2,0);

int j = sc.closeComTemp(2);

String str = sc.readPersonalInfoTemp(2);

System.out.println(i);

System.out.println(j);

System.out.println(str);

}

}

0 0
原创粉丝点击