最近需要用到JNI,所以抽时间学习了下,对于我这个N年没用过C/C++的,从没用过VS2005的java码农来说,真不容易,编译个dll都遇到莫名其妙的问题~~
下面就来一步一步开始JNI之路。
一、通过java类得到.h头文件
首先,我们写一个java类,声明几个native方法
package jni.test; public class JNIWrapper { public native void display(); public native double sum(double x, double y); public native double divide(double x, double y); }
然后,依次执行如下命令,依次得到class和.h文件
编译class ...\src>javac jni\test\JNIWrapper.java 生成头文件 ...\src>javah jni.test.JNIWrapper
到这里就得到了一个名为“jni_test_JNIWrapper.h”的头文件,其内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class jni_test_JNIWrapper */ #ifndef _Included_jni_test_JNIWrapper #define _Included_jni_test_JNIWrapper #ifdef __cplusplus extern "C" { #endif /* * Class: jni_test_JNIWrapper * Method: display * Signature: ()V */ JNIEXPORT void JNICALL Java_jni_test_JNIWrapper_display (JNIEnv *, jobject); /* * Class: jni_test_JNIWrapper * Method: sum * Signature: (DD)D */ JNIEXPORT jdouble JNICALL Java_jni_test_JNIWrapper_sum (JNIEnv *, jobject, jdouble, jdouble); /* * Class: jni_test_JNIWrapper * Method: divide * Signature: (DD)D */ JNIEXPORT jdouble JNICALL Java_jni_test_JNIWrapper_divide (JNIEnv *, jobject, jdouble, jdouble); #ifdef __cplusplus } #endif #endif
经过转换之后,方法名、变量类型什么的都变了,不过都挺有规律的:Java_包名+类名(点都换成下划线)_方法名
二、创建一个dll工程
首先,在VS2005中,点击新建,出现下图
输入Name之后,点击[OK],出现下图:
选择dll,点击finish完成即可创建dll工程
三、编写C/C++代码,生成dll
将步骤一种生成的头文件拷贝到工程中“Header Files”目录下,然后新建一个cpp文件,或者直接在默认生成的jnitest.cpp中编码
// jnitest.cpp : Defines the entry point for the DLL application. // #include "stdafx.h" #include "jni_test_JNIWrapper.h" #include <jni.h> //一定要加上这个 #ifdef _MANAGED #pragma managed(push, off) #endif BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { return TRUE; } #ifdef _MANAGED #pragma managed(pop) #endif JNIEXPORT void JNICALL Java_jni_test_JNIWrapper_display (JNIEnv *env, jobject obj) { printf("Hello World,JNI!\n"); return; } /* * Class: jni_test_JNIWrapper * Method: sum * Signature: (DD)D */ JNIEXPORT jdouble JNICALL Java_jni_test_JNIWrapper_sum (JNIEnv *env, jobject obj, jdouble a, jdouble b) { return a + b; } JNIEXPORT jdouble JNICALL Java_jni_test_JNIWrapper_divide(JNIEnv *env, jobject obj, jdouble a, jdouble b) { return a/b; }
然后我们就可以开始编译了。
如果提示找不到“jni.h”,只需要做如下操作即可解决:
在%JAVA_HOME%\include\下找到 jni.h, 在%JAVA_HOME%\include\win32\下找到jni_md.h和jawt_md.h 把他们复制到“Visual Studio目录\VC\include\”下
四、继续完成Java代码调用dll
将步骤三得到的jnitest.dll放到java工程的根目录,注意是java项目的根目录,不是src目录
写个test方法测试下
package jni.test; public class JNITest { static { System.loadLibrary("jnitest"); } public static void main(String[] args) { JNIWrapper wrapper = new JNIWrapper(); wrapper.display(); System.out.println(wrapper.sum(1.0, 9.9999)); System.out.println(wrapper.divide(8.4, 2.4)); } }
不过,多数情况下,我们会把System.loadLibrary("jnitest")放在JNIWrapper中,即,
package jni.test; public class JNIWrapper { static { System.loadLibrary("jnitest"); } public native void display(); public native double sum(double x, double y); public native double divide(double x, double y); }
运行一下,输入结果为
10.9999
3.5000000000000004
Hello World,JNI!
不知道打印“Hello World,JNI!”怎么最后执行~奇怪~
到这里,整个JNI调用过程就over了~~
不过还有类型转换什么的,以后再整理了....