有時候吧,一個項目不是由單一的某種語言構成的,所以避免不了語言與語言之間的協作關係。
比如:這時你的項目部分是用JAVA編寫的,你需要對資料進行加密與解密的操作,一般來說你會用JAVA實現一個密碼編譯演算法。不過呢,現在你手頭上有個非JAVA的組件可以用,比如DLL,考慮到效率上的問題你使用這個DLL更好些。這時候你就得使用JNI(JAVA NATIVE INTERFACE)—JAVA 原生介面。
這樣我們從一個JAVA調用一個存在的DLL例子入手吧。
DES.dll 調用介面如下:
| 1、 加密 I=Encrypt(對象,密文, 明文, 密鑰) I=1時加密成功;I=0時加密失敗 ;I為整型變數 函數:int Encrypt(void * objptr,char* OutBuffer,LPSTR DataInBuffer,LPSTR KeyInBuffer) 輸入參數: CString DataInBuffer,要加密的明文 CString KeyInBuffer 加密金鑰 要求:8-16個字元,(實際範圍0-16字元) 輸出參數: char* OutBuffer, 加密後的密文 格式:(明文字元數/8+1)*16 2、 解密I=Decrypt(對象,原文,密文, 密鑰) I=1時加密成功;I=0時加密失敗 ;I為整型變數 函數:int Decrypt(void * objptr,char * OutBuffer,LPSTR DataInBuffer,LPSTR KeyInBuffer) 輸入參數: CString DataInBuffer,要解密的密文 無格式要求 CString KeyInBuffer 解密密鑰 要求:8-16個字元,(實際範圍0-16字元) 輸出參數: char* OutBuffer, 解密後的明文 格式:原文字串 3、對象void * CreateDES_Dll() |
首先,實現一個JAVA代碼,聲明原生函數和參數。
| package com.daxiannetwork.util; public class JDES { /** * Kaede */ static{ System.loadLibrary("com_daxiannetwork_util_JDES"); } public native String Decrypt(String cryptograph,String key); //聲明的原生函數Decrypt,用於解密 public native String Encrypt(String proclaim,String key); //聲明的原生函數Encrypt,用於加密 public static void main(String[] args) { JDES jdes=new JDES(); String a=jdes.Encrypt("123","1") //1為密鑰 String b=jdes.Encrypt(a,"1"); System.out.println(a+":"+b); } } |
然後,編譯(這裡不敘述),產生JDES.class。
接下來,用javah.exe產生C的標頭檔。
這個必須說一下,由於我們這個類包含在com.daxiannetwork.util中。
| javah -jni -d D:/eclipse/workspace/GUI/com/daxiannetwork/util com.daxiannetworkt.util.JDES |
在這個目錄下D:/eclipse/workspace/GUI/com/daxiannetwork/util 有一個com_daxiannetwork_util_JDES.h
這個就是我們要得到的標頭檔。
#include "jni.h" #ifndef _Included_com_daxiannetwork_util_JDES #define _Included_com_daxiannetwork_util_JDES #ifdef __cplusplus extern "C" { #endif /* * Class: com_daxiannetwork_util_JDES * Method: Decrypt * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_daxiannetwork_util_JDES_Decrypt (JNIEnv *, jobject, jstring, jstring); /* * Class: com_daxiannetwork_util_JDES * Method: Encrypt * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_daxiannetwork_util_JDES_Encrypt (JNIEnv *, jobject, jstring, jstring); #ifdef __cplusplus } #endif #endif |
看看,跟正常的C標頭檔有什麼差別,
JNIEXPORT jstring JNICALL Java_com_daxiannetwork_util_JDES_Encrypt (JNIEnv *, jobject, jstring, jstring);
JNIEXPORT,JNICALL這是宏,將被展開為平台專有的指令。JNIEnv , jobject, jstring, jstring 都是
JNI定義的資料類型。
Java_com_daxiannetwork_util_JDES_Encrypt 這個是函數名,所有的原生函數都以Java作為標識,後面是包名方法名。呵呵,這樣使得C++代碼必須實現這樣的方法,可是原有的dll函數不是這樣的,
所以我採用java—>yourDLL—>otherDLL。
現在我們來實現自己的DLL吧!
用VC++建立一個com_daxiannetwork_util_JDES MFC 動態串連庫的項目(由於已經存在的DLL是用MFC實現的),然後將%JAVA_HOME%/include與%JAVA_HOME%/include/win32下的.h檔案加入到項目中,
接著,修改VC++項目產生的com_daxiannetwork_util_JDES.h,將JAVAH產生的.h檔案用記事本開啟、複製
所有內容,粘貼到VC++項目產生的com_daxiannetwork_util_JDES.h,最前面。
實現這個本地函數,開啟com_daxiannetwork_util_JDES.cpp,加入以下代碼,如下。
#include "com_daxiannetwork_util_JDES.h" //將調用的DLL標頭檔 #include "DES_DLL_I.h" JNIEXPORT jstring JNICALL Java_com_daxiannetwork_util_JDES_Decrypt (JNIEnv *env, jobject obj, jstring cryptograph,jstring key) { const char *T_cryptograph = env->GetStringUTFChars(cryptograph, 0); const char *T_key = env->GetStringUTFChars(key, 0); void * objptr = CreateDES_Dll(); char * OutputStr = new char[1000]; char mingwen[1000]; int result = Decrypt(objptr,OutputStr,T_cryptograph,T_key); strcpy(mingwen,OutputStr); //告訴VM本地代碼不在有權使用UTF env->ReleaseStringUTFChars(cryptograph, T_cryptograph); env->ReleaseStringUTFChars(key, T_key); delete [] OutputStr; return env->NewStringUTF(mingwen); } //加密 JNIEXPORT jstring JNICALL Java_com_daxiannetwork_util_JDES_Encrypt (JNIEnv *env, jobject obj, jstring proclaim,jstring key) { const char *T_proclaim = env->GetStringUTFChars(proclaim, 0); const char *T_key = env->GetStringUTFChars(key, 0); void * objptr = CreateDES_Dll();//調用other dll 中的一個方法。 char * OutputStr = new char[1000]; char miwen[1000]; int result = Encrypt(objptr,OutputStr,T_proclaim,T_key);//調用other dll 中的一個方法。 strcpy(miwen,OutputStr);
env->ReleaseStringUTFChars(proclaim, T_proclaim); env->ReleaseStringUTFChars(key, T_key); delete [] OutputStr; return env->NewStringUTF(miwen); } |
編譯,產生com_daxiannetwork_util_JDES.dll,然後將這兩個DLL註冊到PATH中。
運行程式。
呵呵,這個介紹了調用第3方的DLL,但是不適合出學者。其實都是一樣的,就是JDES.class與com_daxiannetwork_util_JDES.dll溝通。
將紫色部分去掉就是只有JDES.class與com_daxiannetwork_util_JDES.dll溝通了,呵呵,就是直來直去。
呵呵,關於JNI更詳細的請見:
http://java.sun.com/j2se/1.3/docs/guide/jni/spec/jniTOC.doc.html
JNI調用已經存在的dll,呵呵 文章寫的不好。見諒!!
有問題這裡問就好了,我經常來的。