JNI初步。让大家一看就会哈哈。
写篇教程吧,网上很多关于JNI的hello world,虽然称作哈喽沃德,但是调试起来还是不可避免遇到很多问题。今天在调式成功的这个里程碑时间里,总结下这两天俺的经验,那些希望使用JNI的银们,如果看到这篇小文了,或许可以一站式解决问题,免去东奔西走的麻烦咧~~~~哈哈哈
开始!
JNI是啥就不介绍了,最直观的作用就是它可以在java里面调用dll。如果大家伙儿遇到c++写的代码想转向java使用,不妨生成一个dll,再按下面的步骤来。
1. 编写java代码。文件名:HelloWorld.java
代码如下:
public class HelloWorld
{
static
{
System.loadLibrary("HelloWorldDll");
}
public native static int MyMethod();
public static void main(String[] args)
{
HelloWorld hw = new HelloWorld();
hw.MyMethod();
}
}
2. 编译java代码,生成class文件。
在命令行下输入:javac HelloWorld.java
完成后,D盘根目录下产生了HelloWorld.class文件。
PS:如果这里出现问题没有成功,那请检查你的环境变量是否设置正确。以及确认命令提示符是在当前你要编译的java文件的位置。以下是错误举例:
问题1:
出错原因:你肯定粗心了,在代码中使用的类名和文件名不一致。图中所示错误是将类名写成了HelloWorlds。
3. 根据class文件生成HelloWorld.h,以供C++调用。
在命令行下输入:javah HelloWorld
完成后,D盘根目录下产生了HelloWorld.h文件。
生成的代码如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: MyMethod
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_HelloWorld_MyMethod
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
这里需要做一点改动,将第二行的#include <jni.h>改成#include “jni.h”。否则vc生成dll编译的时候可能产生问题。
以下是这一步骤的错误举例:
问题一:
出错原因:编写的java程序中出现了包的说明:package com.microsoft.services;将包去掉就中了。关于带包编译的情况,下面分解。
4. 使用VC++创建dll程序。文件名:HelloWorldDll.dll
4.1新建一个名叫HelloWorldDll的dll工程:
4.2在HelloWorldDll.cpp文件头部加入:#include “HelloWorldDll.h”
4.3在HelloWorldDll.cpp文件中再加入:
JNIEXPORT jint JNICALL Java_HelloWorld_MyMethod (JNIEnv *, jclass)
{
printf("this is helloworld printed in dll");
return 1;
}
代码中的jint是指名java中的返回值类型为int型。Java_后面跟上java文件的类名,然后再用一个_跟上方法名。括号中的参数不必做改动。
这里需要注意的有两点:
第一, 如果类带有包。那么Java_HelloWorld_MyMethod的第一个_前面需要把包名加上,改成Java_<包名>_HelloWorld_MyMethod。详细示例一会儿继续往下看。
第二, 第二,如果希望传入参数,那么在后面继续加就是了,例如,我想传入int型的变量a,那么第一行需要改成:
JNIEXPORT jint JNICALL Java_HelloWorld_MyMethod (JNIEnv *, jclass,jint a)
函数体内a就可以拿来随意整了。
编译生成dll文件吧。
出错举例:
错误1:
C:\work\VCProjects\HelloWorldDll\HelloWorldDll.cpp(6) : fatal error C1083: Cannot open include file: 'HelloWorld.h': No such file or directory
原因:没有把D盘下的HelloWorld.h拷贝到工程目录下面。
错误2:
c:\work\vcprojects\helloworlddll\helloworld.h(2) : fatal error C1083: Cannot open include file: 'jni.h': No such file or directory
原因:没有把jni.h拷贝到工程目录下。Jin.h的位置:
C:\Program Files\Java\jdk1.5.0_06\include
错误3:
c:\work\vcprojects\helloworlddll\helloworld.h(2) : fatal error C1083: Cannot open include file: 'jni.h': No such file or directory
原因:呵呵为什么我已经把jni.h拷贝到工程目录下了,还是会报这个错误呢?那是因为HelloWorld.h里面的#include <jni.h>忘了改成#include “jni.h”。
错误4:
c:\work\vcprojects\helloworlddll\jni.h(27) : fatal error C1083: Cannot open include file: 'jni_md.h': No such file or directory
原因:又是找不到.h。这个jni_md.h藏在
C:\Program Files\Java\jdk1.5.0_06\include\win32下面。
5. 运行看效果。
将刚才生成的HelloWorldDll.dll拷贝到D盘根目录下,从命令行执行:
Java HelloWorld
可以看到运行结果了吧。
恭喜你,成功了。
但是这样就可以了吗?显然平时过程中大都不是在命令行下执行的。接下来,我们去看看在eclipse里面会不会一帆风顺捏?
1. 新建一个Web工程。工程名叫做HelloWorld。
PS:为什么要建立的是Web工程呢?因为我们不但要在eclipse里面调通,还希望在浏览器中可用。哇哈哈,眼光真远大。
2. 新建一个包叫做com.microsoft.services,以及HelloWorld类。
将刚才的HelloWorld.java中的代码复制进来。最终代码如下:
package com.microsoft.services;
public class HelloWorld {
static
{
System.loadLibrary("HelloWorldDll");
}
public native static int MyMethod();
public static void main(String[] args)
{
HelloWorld hw = new HelloWorld();
hw.MyMethod();
}
}
3. 生成class文件。
刚才的代码编辑完成后,如果没有错误,在点击保存的时候eclipse会自动在以下目录中生成对应的class文件:
C:\work\workspace\HelloWorld\WebRoot\WEB-INF\classes\com\microsoft\services
4. 生成h文件。
这一步很关键。如果按照刚才那样到class所在目录下生成的话,是不行的。因为这里需要用到带包编译。在命令行中cd到
C:\work\workspace\HelloWorld\WebRoot\WEB-INF\classes\路径下,然后输入:
Javah com.microsoft.services.HelloWorld
成功后会在C:\work\workspace\HelloWorld\WebRoot\WEB-INF\classes下发现:
com_microsoft_services_HelloWorld.h文件。
5. Vc中建立dll工程。在cpp中添加的代码也有变动:
5.1引入的头文件:#include "com_microsoft_services_HelloWorld.h"
5.2功能实现:
JNIEXPORT jint JNICALL Java_com_microsoft_services_HelloWorld_MyMethod
(JNIEnv *, jclass);
{
printf("this is helloworld printed in dll");
return 1;
}
6. 编译生成HelloWorldDll.dll。将其放入C:\WINDOWS\system32下,或者放到其他可以让系统通过环境变量找到的位置。
错误1:
java.lang.UnsatisfiedLinkError: no HelloWorldDll in java.library.path
at java.lang.ClassLoader.loadLibrary(Unknown Source)
at java.lang.Runtime.loadLibrary0(Unknown Source)
at java.lang.System.loadLibrary(Unknown Source)
at com.microsoft.services.HelloWorld.<clinit>(HelloWorld.java:6)
Exception in thread "main"
系统没有找到你生成的dll。那表明你的dll放置的位置不对。这里有一个好办法,可以很省事,不用在system32、include、bin等地方拷来拷去的试验。我们在java代码中添加一句:
System.out.println(System.getProperties().get("java.library.path"));然后将一些代码注释掉。
如下所示:
package com.microsoft.services;
public class HelloWorld {
static
{
//System.loadLibrary("HelloWorldDll");
}
public native static int MyMethod();
public static void main(String[] args)
{
System.out.println(System.getProperties().get("java.library.path"));
// HelloWorld hw = new HelloWorld();
// hw.MyMethod();
}
}
运行java程序的时候会看到:
已经将java.library.path显示出来了,我们按指引随意拷贝进去,就可以成功咧!
7. 运行,console里面什么都没出现那么说明成功了,dll中printf的东东是不会显示的。为了验证是否真的成功了,可以打印出方法的返回值,修改HelloWorld.java如下:
package com.microsoft.services;
public class HelloWorld {
static
{
System.loadLibrary("HelloWorldDll");
}
public native static int MyMethod();
public static void main(String[] args)
{
//System.out.println(System.getProperties().get("java.library.path"));
HelloWorld hw = new HelloWorld();
int t = hw.MyMethod();
System.out.println(t);
}
}
在执行,就可以看到1已经乖乖显示在了console里。Yeah!
最后,以上执行都没有问题的话,将其使用在web上也不成问题了哈哈。打完收工!
http://www.chinaunix.net 作者:ludejun98发表于:2004-03-03 11:16:06 最近项目中设计到JNI的技术,对于VC++我是一知半解.JNI是知道和Native方法的接口,从来没用过.但是摸了一会,还是感觉有点门路,搞定了JNI的难题以后,对于自己这点小小的进步不敢隐瞒,公开出来给还不
//////////////////////////////////// ///////////////////////////////////// eclipse+VC6.0开发JNI (1)
|