java 調用第三方dll

來源:互聯網
上載者:User

最近由於搞畢業設計的需要,使用J2EE做一個實驗預約系統,其中涉及到一卡通和IC卡讀卡機,弄來一個刷卡機,廠商只提供了一個用C編寫的Windows動態連結程式庫SmartCom411SFJ.dll,我需要使用java程式調用這個dll檔案來擷取一卡通中的資訊。其實我用到的函數很簡單,這有三個:

串口初始化函數:int  IniCom(int ComPort,int BaudRate)

讀卡資訊函數:int ReadPersonalInfo(int ComPort,unsigned char *Name,unsigned char *buffer)

關閉串口函數:int CloseCom(int ComPort)

上網查過很多資料,得知可以使用JNI調用本地DLL檔案,網上也有很多朋友提出類似問題,但是看了很多網友的回答結果還是不能解決自己遇到的問題,好多回答都是從別人的網頁上copy一些代碼,沒有講述如何調用第三方的DLL檔案,開啟很多網頁發現裡面講的內容都是一樣的,甚至還有很多代碼貼出來都是錯誤的,根本就沒有對提問者的問題做出回答,真正要找的解決辦法卻很難。

我開始也嘗試網上說的辦法來做:

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);//返回用name和buffer中的資訊,中間用”|”分割開

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

}

}

 

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/rohsuton/archive/2008/12/29/3637272.aspx#1571539

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.