即使是基于windows平台,在一般情况下,Java就够用了,或者单独的C++也够用,但由于一些第三方调用以及往系统底层调用的情形,我们往往避免不了互相调用。这不最近Java desktop application用到usb-key,需要调用它的库进行加密、文件读写,重拾了JNI技术,写个帖子留念下。
一般来说Java调用C++的话一般是通过JNI;而C++调用Java的话一般是靠C++启动jvm,在这个jvm环境里执行java class。这种互调几年以很流行,记得当时IBM还弄了一套专门的基于eclipse的插件工具(DTJCB:development tool for Java COM Bridge),它可以实现双向调用,能自动生成许多代码,功能很是强大,而且是前绑定,效率比较高,但不知为何后来不更新了。目前用的比较多的jacob,是基于后绑定的,个人感觉参数用起来很诡异,不习惯。
JNI(Java Native Interface),即Java本地化接口,下面谈谈它的一般开发步骤:
1.在java 类中写native方法,它就像定义abstract方法一样,不过就是把abstract换成native。
比如定义了类TestJNI和native方法
package org.csdn;
public class TestJNI
{
static
{
System.loadLibrary("TestJNI");
}
public native String restoreLicense(String content);
}
2.javah生成C端的头文件,注意这步有前提:注册了环境变量,包括JAVA_HOME,PATH,CLASSPATH;
在cmd进入TestJNI所在class目录,比如为【D:/workspace/Test/bin/org/csdn】,然后执行javah命令
D:/workspace/Test/bin/org/csdn>javah -classpath D:/workspace/Test/bin/org/csdn org.csdn.TestJNI
要注意这里的目录,以及包名
执行成功以后,会在【D:/workspace/Test/bin/org/csdn】目录下看到org_csdn_TestJNI.h这个C端的头文件,它包含一个接口:
/*
* Class: org_csdn_TestJNI
* Method: restoreLicense
* Signature: (Ljava/lang/String;)Z
*/
JNIEXPORT jstring JNICALL Java_org_csdn_TestJNI_restoreLicense (JNIEnv *, jobject, jstring);
3.建立Win32 Dynamic-Link Library 的C++工程,工程名为TestJNI,并实现头文件。把org_csdn_TestJNI.h拷贝到工程目录下,然后添加类org_csdn_TestJNI.cpp实现它。org_csdn_TestJNI.cpp中的方法实现:
#include <jni.h>
#include "org_csdn_TestJNI.h"
JNIEXPORT jstring Java_org_csdn_TestJNI_restoreLicense(JNIEnv *env, jobject obj, jstring content)
{
....
return NewJString(env, 0);
}
可能会找不到jni.h头文件,需要去%JAVA_HOME%/include目录下拷贝jni.h以及%JAVA_HOME%/include/win32目录下拷贝jawt_md.h和jni_md.h,粘贴到%VISUALSTUDIO_HOME%/VC98/Include目录下去。
4.编译并构件C++工程TestJNI,生成TestJNI.dll,拷贝到Java工程TestJNI的根目录下,即可运行Java测试刚才的工作。
------------------------------------------------------------------------
附带几个JNI中常用类型转换的方法:
/**
LPCTSTR转换成jstring
*/
jstring NewJString(JNIEnv * env, LPCTSTR str)
{
if (!env || !str)
return 0;
int slen = strlen(str);
jchar * buffer = new jchar[slen];
int len = MultiByteToWideChar(CP_ACP, 0, str, strlen(str), buffer, slen);
if (len > 0 && len < slen)
buffer[len] = 0;
jstring js = env->NewString(buffer, len);
delete [] buffer;
return js;
}
/**
jstring转换成char*
*/
char* jstringTostring(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
}
另外jboolean 可以直接用true和false。
971

被折叠的 条评论
为什么被折叠?



