一 Java端
----------------------------------------------------------------------------------begin
import java.io.UnsupportedEncodingException;
public class DESInvokeLib {
static {
System.loadLibrary("encrypt");
}
public native static byte[] encrypt(int len, byte[] str);
public native static byte[] decrypt(byte[] str);
public static void main(String[] args) {
DESInvokeLib desInvokeLib = new DESInvokeLib();
String plainText = "Welcome to My Jni Test! -wangfei/n" +
"1Welcome to My Jni Test! -wangfei/n" +
"2Welcome to My Jni Test! -wangfei/n" +
"Emai: vinch.wang@gmail.com/n";
System.out.println("plain text is: " + plainText);
try {
//将String转换为字符数组
byte[] plainTextBytes = plainText.getBytes("ISO-8859-1");
int len = plainTextBytes.length;
System.out.println("plainTextBytes length is: " + len);
//先加密,再解密
byte[] encryptedTextBytes = desInvokeLib.encrypt(len, plainTextBytes);
byte[] decryptedTextBytes = desInvokeLib.decrypt(encryptedTextBytes);
//将字符数组转换为String
System.out.println("decryptedTextBytes length is: " +
decryptedTextBytes.length);
String decryptedText = new String(decryptedTextBytes, "ISO-8859-1");
System.out.println("decryptedText is: " + decryptedText);
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
----------------------------------------------------------------------------------end
保存为DESInvokeLib.java文件, 先编译生成class文件, 再用"javah DESInvokeLib"命令生成包含dll函数导出声明的头文件"DESInvokeLib.h". 具体内容如下:
----------------------------------------------------------------------------------begin
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class DESInvokeLib */
#ifndef _Included_DESInvokeLib
#define _Included_DESInvokeLib
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: DESInvokeLib
* Method: encrypt
* Signature: (I[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_DESInvokeLib_encrypt
(JNIEnv *, jclass, jint, jbyteArray);
/*
* Class: DESInvokeLib
* Method: decrypt
* Signature: ([B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_DESInvokeLib_decrypt
(JNIEnv *, jclass, jbyteArray);
#ifdef __cplusplus
}
#endif
#endif
----------------------------------------------------------------------------------end
二 VC端
1. 在VC6的"Tool->Options"下, 添加java的库文件路径.
如C:/JDK 1.5.0/INCLUDE 和 C:/JDK1.5.0/INCLUDE/WIN32.
2. 建立"Win32 Dynamic-Link Library"类型的空工程, 导入DES.cpp, DES.h. DESInvokeLib.h文件.
工程名存为"encrypt".
3. 在encrypt.cpp文件内编写代码, 具体如下
----------------------------------------------------------------------------------begin
#include "windows.h"
#include "jni.h"
#include "Des.h" //参照原DES加密程序
#include "DESInvokeLib.h" //参照原DES加密程序
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
JNIEXPORT jbyteArray JNICALL Java_DESInvokeLib_encrypt
(JNIEnv *jniEnv, jclass, jint length, jbyteArray jarrByte)
{
//接收明文
jbyte* pJbyte = jniEnv->GetByteArrayElements(jarrByte, 0);
char* szByte = (char *)pJbyte;
//显示调试信息
printf("/ncome-in: /n%s, %d/n",szByte, strlen(szByte));
//定义Key和Buffer
char key[] = {0,2,0,0,9,3,5,1,9,8,0,0,9,1,7};
char buf[255];
//存明文到buffer并加密
memset( buf, 0, sizeof(buf) );
strcpy( buf, szByte );
/*消除java与c转换产生的多余字符*/
buf[length] = '/0';
//参照原DES加密程序
Des_Go(buf, buf, strlen(buf), key, sizeof(key), ENCRYPT);
//生成结果并返回
jbyteArray jarrRet = jniEnv->NewByteArray( strlen(buf) );
strcpy( szByte, buf );
jniEnv->SetByteArrayRegion( jarrRet, 0, strlen(buf), (jbyte *)szByte );
jniEnv->ReleaseByteArrayElements(jarrRet, pJbyte, 0);
return jarrRet;
}
JNIEXPORT jbyteArray JNICALL Java_DESInvokeLib_decrypt
(JNIEnv *jniEnv, jclass, jbyteArray jarrByte)
{
//接收
jbyte* pJbyte = jniEnv->GetByteArrayElements(jarrByte, 0);
char* szByte = (char *)pJbyte;
//定义Key和Buffer
char key[] = {0,2,0,0,9,3,5,1,9,8,0,0,9,1,7};
char buf[256];
//存明文到buffer并加密
memset( buf, 0, sizeof(buf) );
strcpy( buf, szByte );
// 参照原DES加密程序
Des_Go(buf, buf, strlen(buf), key, sizeof(key), DECRYPT);
//生成结果并返回
jbyteArray jarrRet = jniEnv->NewByteArray( strlen(buf) );
strcpy( szByte, buf );
//显示调试信息
printf("/nout: /n%s, %d /n/n",szByte, strlen(szByte));
jniEnv->SetByteArrayRegion( jarrRet, 0, strlen(buf), (jbyte *)szByte );
jniEnv->ReleaseByteArrayElements(jarrRet, pJbyte, 0);
return jarrRet;
}
----------------------------------------------------------------------------------end
4. 为方便起见,在VC6的"Project->Settings->Link->General"中,设置dll导出路径为java文件所在路径.
5. 按F7编译生成dll, 并在控制台中运行java程序, 命令如 "java DESInvokeLib", 可见结果.
三 小结
1. java与vc之间传递参数, 如果是整数类型(int), 一般不会有问题, 但如果是传递字符串,则要考虑的问题较多.
java程序编译时使用的是unicode编码, 传输时使用的是utf-8格式, 而vc6默认使用的是ansi编码.
2. 传递字符串, 在java端可以选择参数类型为 String 或者 byte[], 如果选择String,则与vc6配合做参数传递时,问题多多,还会生成不少乱码. 如果选择使用 byte[], 则处理起来容易一些,问题也要少一些.
3. 为了解决参数传递中产生的乱码问题, 所以特别在参数中加入字符串长度 len, 并在vc6收到字符串后,
用 " buf[length] = '/0' " 命令做处理. 实践表明, 效果还比较理想.
ps: 未解决的问题
1. 在vc6中接收java传递过来的字符串参数, 会在正常字符串内容的末尾产生多余的乱码.
2. DES程序能处理的明文长度只到255. 即buf变量定义长度.
参考:
1. http://www.vckbase.com/code/viewcode.asp?id=1897
2. http://www.iplab.cs.tsukuba.ac.jp/~liuxj/jdk1.2/zh/docs/guide/jni/spec/jniTOC.doc.html
3. http://www.sagewire.org/java-programmer/JNI-DLL-VC-173069.aspx