Java通過JNI調用dll詳細過程

來源:互聯網
上載者:User

標籤:

源:Java通過JNI調用dll詳細過程

  最近項目有這樣一個需求,在已有的CS軟體中添加一個連結,將當前登入使用者的使用者名稱加密後放在url地址中,在BS的login方法裡通過解密判斷,如果為合法使用者則無需再次登入直接進入平台,CS軟體方提供了一個加密解密的dll檔案,我們需要在action中通過該dll解密,那麼就涉及到java調用dll的問題。

 

  首先我選擇了JNI方式(因為網上說的另兩種方式Jawin, Jacob更不會),大體流程如下:

  1、寫一個java的class,在類裡聲明所調用的庫名稱和需要使用的函數(注意:需要對方法做本地聲明,關鍵字為native。且只需要聲明,而不需要具體實現)

package com;public class javacall{        static        {                System.loadLibrary("htgsjencrypt");        }               public native static String DecodeString(char[] szSrc);        public native static String EncodeString(char[] szSrc);        private static void printCharArray(char[] content)        {            String temp=new String(content);            System.out.println(temp);        }        public static void main(String[] args)        {          String s="123";          char[] src=new char[100];          src=s.toCharArray();          String encode="";          printCharArray(src);          encode=javacall.EncodeString(src);          System.out.println("encode="+encode);          String decode="";          src=encode.toCharArray();          decode=javacall.DecodeString(src);          System.out.println("decode="+decode);                  }}

  這個地方需要提一下,建立這個class時最好不要建在預設包中,將來對這個工程打包後,在引用的工程中無法找到預設包中的class(也許是我寫的不對,不過寫在預設包中確實會帶來不必要的麻煩)

  2、對於以上編譯好的class檔案通過使用javah命令產生標頭檔javacall.h,這個檔案需要被C++程式調用來產生所需的庫檔案

/* DO NOT EDIT THIS FILE - it is machine generated */#include "jni.h"/* Header for class com_javacall */#ifndef _Included_com_javacall#define _Included_com_javacall#ifdef __cplusplusextern "C" {#endif/* * Class:     com_javacall * Method:    DecodeString * Signature: ([C)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_javacall_DecodeString  (JNIEnv *, jclass, jcharArray);/* * Class:     com_javacall * Method:    EncodeString * Signature: ([C)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_javacall_EncodeString  (JNIEnv *, jclass, jcharArray);#ifdef __cplusplus}#endif#endif

  這裡需要提到一點,預設產生的標頭檔中寫的是

#include <jni.h>

  在C++的calss中引用時編譯報錯找不到jni.h,可以去jdk安裝包的include檔案夾中拷貝jni.h、jni_md.h、jawt_md.h三個檔案到程式目錄,這時再編譯可能還報找不到jni.h的錯誤,可以將#include <jni.h>改為#include "jni.h",因為前者是引用系統標頭檔的寫法

  3、在VC中建立一個庫檔案htgsjencrypt,在建立的class檔案中實現java標頭檔中聲明的兩個加密解密方法,因為第三方沒有提供.lib檔案,也沒有.h檔案,那麼只能用動態使用連結庫的方式來調用dll了,具體代碼如下:

#include "gsjencrypt.h"#include "com_javacall.h"#include "windows.h"#include <iostream>//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////gsjencrypt::gsjencrypt(){}gsjencrypt::~gsjencrypt(){}typedef int (WINAPI *FDecodeString)(char szSrc[100], char szDest[100]);typedef int (WINAPI *FEncodeString)(char szSrc[100], char szDest[100]); JNIEXPORT jstring JNICALL Java_com_javacall_EncodeString(JNIEnv * env, jclass jobject, jcharArray src){    HINSTANCE hDLL;    hDLL=LoadLibrary("gsjencrypt.dll");//載入動態連結程式庫gsjencrypt.dll檔案;    if(hDLL==NULL)        return 0;    FEncodeString encodeString=(FEncodeString)GetProcAddress(hDLL,"EncodeString");    jsize size = (env)->GetArrayLength(src);    jchar * arrayBody = (env)->GetCharArrayElements(src,0);     //char * csrc=(char *)arrayBody;        char csrctemp[100]="";    int k=0;    while(size!=0)    {        csrctemp[k]=*arrayBody;        *arrayBody++;        size--;        k++;    }    char cdesttemp[100]="";    encodeString(csrctemp,cdesttemp);    (env)->ReleaseCharArrayElements(src,arrayBody,0);    return (env)->NewStringUTF(cdesttemp);}JNIEXPORT jstring JNICALL Java_com_javacall_DecodeString(JNIEnv * env, jclass jobject, jcharArray src){    HINSTANCE hDLL;    hDLL=LoadLibrary("gsjencrypt.dll");//載入動態連結程式庫gsjencrypt.dll檔案;    if(hDLL==NULL)        return 0;    FDecodeString decodeString=(FDecodeString)GetProcAddress(hDLL,"DecodeString");    jsize size = (env)->GetArrayLength(src);    jchar * arrayBody = (env)->GetCharArrayElements(src,0);     char * csrc=(char *)arrayBody;    char csrctemp[100]="";    int k=0;    while(size!=0)    {        csrctemp[k]=*arrayBody;        *arrayBody++;        size--;        k++;    }    //arrayBody=(env)->GetCharArrayElements(dest,0);     //char * cdest=(char *)arrayBody;    char cdesttemp[100]="";    decodeString(csrctemp,cdesttemp);    (env)->ReleaseCharArrayElements(src,arrayBody,0);    return (env)->NewStringUTF(cdesttemp);}

  這裡需要注意的是

typedef int (WINAPI *FDecodeString)(char szSrc[100], char szDest[100]);typedef int (WINAPI *FEncodeString)(char szSrc[100], char szDest[100]); 

  以上兩個方法是原始dll中提供給外界調用的函數介面,聲明時一定要記得加WINAPI,否則調用時始終報錯。

  4、最後將第三方提供的gsjencrypt.dll和新產生的htgsjencrypt.dll同時拷貝到java.library.path裡(jdk或者jre的bin檔案中),然後將最開始寫的java程式打包即可被別的工程調用。

  記錄一下最難解決的問題,就是不知道怎樣在c++中返回給java解密後的串,因為總是想把指標的概念與java中的某個byte數組或者char數組關聯起來,始終不能成功,最後嘗試使用NewStringUTF才解決問題,哎,C++已經六年沒用過了,真是費勁啊

Java通過JNI調用dll詳細過程(轉)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.