首页 > 编程语言 > c/c++ > Java Jni调用并编写dll详细教程
2014
04-23

Java Jni调用并编写dll详细教程

JNA虽然可以直接调用Windows标准DLL,但是不支持64位DLL,如今使用64位JDK的机器越来越多,JNA反而成了鸡肋。

使用JNI,需要为C\C++生成JAVA调用约定头文件,并对标准windows DLL源码进行适当修改。以下以一个简单的例子演示整个过程。
环境:win7 64位操作系统,JDK1.7 64位,vs2010(安装x64编译支持)。

一,编写native声明的类

package com.ninecmd;

public class MyClass {
static
{
System.loadLibrary("jnidll");
}
public native static void SayHello(String word);
public native static String RepeatWord(String word);
/*public static void main(String[] args)
{
SayHello("hello");
String str = RepeatWord("么么哒");
System.out.println(str);
}
*/
}

“SayHello”,“RepeatWord”为将来dll文件中的函数声明。这个类的作用是生成C\C++头文件
二,生成C\C++头文件
这里需要注意classpath的路径问题。本例中MyClass 类的完整路径为E:\src\com\ninecmd\MyClass.java,类的包名为com.ninecmd,所以classpath应设置为E:\src。

将cmd切换至E:\src。
1、编译MyClass,在同目录生成MyClass.class

E:\src>javac com\ninecmd\MyClass.java

2、生成头文件(注意classpath路径设置)

E:\src>javah -classpath E:\src -d com\ninecmd\ -jni com.ninecmd.MyClass

javah参数说明:

javah -classpath 类目录 -d 头文件输出目录 -jni 完整类名

此时在E:\src\com\ninecmd目录中生成了com_ninecmd_MyClass.h文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_ninecmd_MyClass */

#ifndef _Included_com_ninecmd_MyClass
#define _Included_com_ninecmd_MyClass
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_ninecmd_MyClass
 * Method:    SayHello
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_com_ninecmd_MyClass_SayHello
  (JNIEnv *, jobject, jstring);

/*
 * Class:     com_ninecmd_MyClass
 * Method:    RepeatWord
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_ninecmd_MyClass_RepeatWord
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

三,编写DLL代码
1、本例编写x64 DLL,打开vs2010,创建一个MFC DLL工程。将平台改为x64.
platform

config

2、引入头文件,为了顺眼,我把头文件改名为MyClass.h。
3、编写与头文件声明一致的导出函数。
主要代码:

//将jstring类型转换成windows char*类型
char* jstringToChars( JNIEnv  *env, jstring jstr )
{
	int length = (env)->GetStringLength(jstr );
	const jchar* jcstr = (env)->GetStringChars(jstr, 0 );
	char* rtn = (char*)malloc( length*2+1 );
	int size = 0;
	size = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)jcstr, length, rtn,(length*2+1), NULL, NULL );
	if( size <= 0 )
		return NULL;
	(env)->ReleaseStringChars(jstr, jcstr );
	rtn[size] = 0;
	return rtn;
}

//将windows char*类型转换成jstring类型
jstring CharsTojstring( JNIEnv* env, char* str )
{
	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;
}

JNIEXPORT void JNICALL Java_com_ninecmd_MyClass_SayHello
	(JNIEnv *env, jobject obj, jstring jstr)
{
	char* str = jstringToChars(env,jstr);
	CString out(str);
	AfxMessageBox((out));
}

JNIEXPORT jstring JNICALL Java_com_ninecmd_MyClass_RepeatWord
	(JNIEnv *env, jobject obj, jstring jstr)
{
	return jstr;
}

4、编译发布dll。
四,JNI调用dll
将生成的dll,修改文件名为jnidll.dll,复制到系统System32目录下。将第一步中类代码main函数注释去掉。重新编译类(为保证中文字符串兼容,代码文件需为ANSI编码),并运行测试。
或者用eclipse测试类
SayHello
RepeatWord
测试成功!

五.注意

1.JNI不支持loadlibray的初始化函数,如mfc dll的InitInstance.

最后编辑:
作者:NINE
这个作者貌似有点懒,什么都没有留下。

留下一个回复

你的email不会被公开。