由于项目的需要,最近研究了java 调用DLL的方法,将如何调用的写于此,便于日后查阅:
采用的方法是JNI:Java Native Interface,简称JNI,是Java平台的一部分,可用于让Java和其他语言编写的代码进行交互。
下面是从网上摘取的JNI工作示意图:
总体说明:先在JAVA中建立一个类,通过javac生成.class,再由javah生成.h;然后将.h复制到VC下,由VC实现具体函,
并编译通过后生成DLL,将DLL放入JAVA工程中使用,完毕。
下面说说具体步骤(含实例):
1、建java类:装载DLL,声明要使用DLL方法,具体实现由DLL负责;代码如下:
public class Java2cpp
{
static
{
System.loadLibrary("javaCallcpp");
}
public native int DLL_ADD(int a,int b); //加
public native int DLL_SUB(int a,int b); //减
public native int DLL_MUL(int a,int b); //乘
public native int DLL_DIV(int a,int b); //除
public static void main(String args[])
{
int sum = 0;
Java2cpp test = new Java2cpp();
sum = test.DLL_ADD(2, 4);
System.out.println("Java call cpp dll result:" + sum);
}
}
2、生成.h文件:cmd 到Java2cpp.java目录下,做如下操作:
第一步:javac -encoding UTF-8 Java2cpp.java 生成java2cpp.class
第二步:javah Java2cpp 生成Java2cpp.h头文件,内容如下:
注意:1、Java2cpp.h这个头文件的内容是不能修改的,否则会出错。
2、在javah命令操作时,在src或者bin下,比如:javah -classpath . -jni testDLL.Java2cpp
中间是有个点的。
(目录层级是用"."而不是"\")
3、制做VC动态库:创建一个C/C++动态库工程,命名为javaCallcpp,导入java2cpp.h并实现其方法:
#include "Java2cpp.h"
#include "dllApi.h"
JNIEXPORT jint JNICALL Java_Java2cpp_DLL_1ADD(JNIEnv *env, jobject obj, jint a, jint b)
{
int var = 0;
var = DLL_API_ADD(a,b);
return var;
}
JNIEXPORT jint JNICALL Java_Java2cpp_DLL_1SUB(JNIEnv *env, jobject obj, jint a, jint b)
{
int var = 0;
var = DLL_API_SUB(a,b);
return var;
}
JNIEXPORT jint JNICALL Java_Java2cpp_DLL_1MUL(JNIEnv *env, jobject obj, jint a, jint b)
{
int var = 0;
var = DLL_API_MUL(a,b);
return var;
}
JNIEXPORT jint JNICALL Java_Java2cpp_DLL_1DIV(JNIEnv *env, jobject obj, jint a, jint b)
{
int var = 0;
var = DLL_API_DIV(a,b);
return var;
} //此文件完
加DLL_API_ADD()、减DLL_API_SUB()、乘DLL_API_MUL()、除DLL_API_DIV()四个函数在别一个
文件中实现,文件名是dllApi.cpp,实现如下:
int DLL_API_ADD(int a,int b)
{
return (a+b);
}
int DLL_API_SUB(int a,int b)
{
return (a-b);
}
int DLL_API_MUL(int a,int b)
{
return (a*b);
}
int DLL_API_DIV(int a,int b)
{
return (a/b);
} //此文件完
此时工程还编译不过,因为include出错,需添加JNI所在的目录,如下:
4、编译动态库工程:生成javaCallcpp.dll,并将这个动态库复制到java工程目录下:
5、使用DLL:运行java程序,结果如下:
至此,java调用dll已经完成。
*****************************************************分割线*************************************************************************
如果dll传来的有中文情况,可能会出现乱码。
解决策略为(在自己的项目中第二个方法即
jstring WindowsTojstring(JNIEnv* env, const char* str)
是可以用的):
#include "getChinese.h"
#include "testDLL_Java2cpp.h"
#include
char* jstringToWindows(JNIEnv *env, jstring jstr);
jstring WindowsTojstring(JNIEnv* env, const char* str);
JNIEXPORT jstring JNICALL Java_testDLL_Java2cpp_getResult
(JNIEnv *env, jobject obj, jstring name) {
string str = "hello 你好啊,这是一个测试的dll";
const char* result = str.c_str();
jstring js = WindowsTojstring(env,result);
return js;
/*
if ( r!= NULL){
return env->NewStringUTF(r);
cout << r << endl;
}
else{
//return NULL;
return env->NewStringUTF(result);
}*/
}
char* jstringToWindows(JNIEnv *env, jstring jstr)
{ //UTF8/16转换成gb2312
int length = (env)->GetStringLength(jstr);
const jchar* jcstr = (env)->GetStringChars(jstr, 0);
int clen = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)jcstr, length, NULL, 0, NULL, NULL);
char* rtn = (char*)malloc(clen);
//更正。作者原来用的是(char*)malloc( length*2+1 ),当java字符串中同时包含汉字和英文字母时,所需缓冲区大小并不是 2倍关系。
int size = 0;
size = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)jcstr, length, rtn, clen, NULL, NULL);
if (size <= 0)
return NULL;
(env)->ReleaseStringChars(jstr, jcstr);
rtn[size] = 0;
return rtn;
}
jstring WindowsTojstring(JNIEnv* env, const char* str)
{//gb2312转换成utf8/16
jstring rtn = 0;
int slen = strlen(str);
unsigned short * buffer = 0;
if (slen == 0)
rtn = (env)->NewStringUTF(str);
else
{
int length = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)str, slen, NULL, 0);
buffer = (unsigned short *)malloc(length * 2 + 1);
if (MultiByteToWideChar(CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length) >0)
rtn = (env)->NewString((jchar*)buffer, length);
}
if (buffer)
free(buffer);
return rtn;
}
不管将c++的代码文件如何设置为utf-8 还是会出现中文乱码,所以采用上述的编码方式可以解决这个问题。
*****************************************************贴出java侧的输出结果***********************************
package
testDLL;
public
class
Java2cpp {
static
{
System. loadLibrary(
"callDLL"
);
}
public
native
String getResult(String
in
);
public
static
void
main(String[]
args
) {
//
TODO
Auto-generated method stub
String
result
=
""
;
Java2cpp
test
=
new
Java2cpp();
result
=
test
.getResult(
"李海涛"
);//这里的输入有点多余了
System.
out
.println(
result
);
}
}