计划第三篇写一个java安装程序实例(客户端无jre环境的安装包),以解决java程序(软件)安装不方便的问题,使java程序安装也傻瓜化。 

直接进入正题: 

完成本实例需要下列工具/环境: 
1、java环境 
2、c/cpp编辑器。windows下推荐用vs/vc++,我用的是vs2008。linux下gcc/g++ 

从 C/CPP 程序调用 Java 代码需要四个步骤 : 
一 编写 Java 代码。 
二 编译 Java 代码。 
三 编写 C/C++ 代码。 
四 运行本机 C/C++ 应用程序。 

1、编写java代码 

为了达到示范作用,java方法我用两个,一个是静态方法,一个是普通方法。 

C2java.java 

Java代码  

1. package
2.   
3. public class
4. public
5. super();  
6.     }  
7. public static int add(int a,int
8. return
9.     }  
10. public boolean judge(boolean
11. return
12.     }  
13.   
14. }


静态方法的好处是我不用实例化,直接可以调用方法。调用起来比较简单,不容易出错。 



2、编译java代码 



javac 命令。(略) 



3、编写 C/C++ 代码 



我想在c/cpp中直接生成一个exe然后窗口输出结果,所以我就建立一个exe工程。编辑器jni环境是上篇已经搭建好的,所以这里只需要少量配置就可以了。好了,我们先建立一个工程: 



打开vs2008,新建一 win32 console App 工程 


 


键入工程名字c2java,点击OK,出来窗口点击next,选取console app 


 


点击完成。到这里先不忙编码实现,我们先把环境搭建好,右键工程属性,选取 linker -->input,在右边窗口添加依赖jvm.lib,这个lib的位置在你%JAVA_HOME%/lib 下。如果你的路径中同我一样包含空格(例如Program Files)记得用引号括起来。 



打开stdafx.h文件添加 


C++代码  

1. #include <iostream>
2. #include <jni.h>
3.   
4. #ifdef _WIN32
5. #define PATH_SEPARATOR ';'
6. #else
7. #define PATH_SEPARATOR ':'
8. #endif


打开c2java.cpp,键入下面的代码 


C++代码  

1. using namespace
2.   
3. int
4. {  
5.       
6.   JavaVMOption options[1];  
7.   JNIEnv *env;  
8.   JavaVM *jvm;  
9.   JavaVMInitArgs vm_args;  
10. long
11.   jclass cls;  
12.   jmethodID mid;  
13.   jint square;  
14.   jboolean not;  
15.     jobject jobj;  
16.   
17. "-Djava.class.path=.";  
18.   vm_args.version = JNI_VERSION_1_2;  
19.   vm_args.nOptions = 1;  
20.   vm_args.options = options;  
21. void**)&env, &vm_args);  
22. if
23.   {  
24. "com/testJni/testDemo/C2java");  
25. if(cls !=0)  
26.     {   
27. "add", "(II)I");  
28. if(mid !=0)  
29.         {    
30.                     square = env->CallStaticIntMethod( cls, mid, 5,5);  
31.                     std::cout << square << std::endl;  
32.           }  
33. "<init>","()V");  
34. if(mid !=0)  
35.         {    
36.                     jobj=env->NewObject(cls,mid);  
37. "init ok"
38.           }  
39. "judge","(Z)Z");  
40. if(mid !=0)  
41.         {    
42.                     not = env->CallBooleanMethod(jobj, mid, 1);  
43. if(!not){  
44. "Boolean ok"
45.                     }  
46.         }  
47.                   
48.     }  
49.   
50.     jvm->DestroyJavaVM();  
51. return
52.   }  
53. else
54. return
55.   
56. }


下面解释下上面的代码: 


JavaVMOption options[] 具有用于 JVM 的各种选项设置。声明的 JavaVMOption options[] 数组足够大,就能容纳我们希望使用的所有选项。在本实例中,我们使用的选项就是类路径选项。 


JNIEnv *env 表示 JNI 执行环境。 


JavaVM *jvm 是指向 JVM 的指针。我们主要使用这个指针来创建、初始化和销毁 JVM。JavaVMInitArgs vm_args 表示可以用来初始化 JVM 的各种 JVM 参数。 


设置参数后,创建我们的jvm : 


status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);


成功返回0,不成功返回JNI_ERR。 


创建完成后,我们就可以查找我们的class了,因为我们的java类一般都有包,所以我们也要加上包路径com/testJni/testDemo/C2java 



在这里我们会使用到java的一个命令javap ,这个命令有什么用那,我们用javap -s -p C2java看看 


 


打开jni.h我们会发现,Signature就是sig,也就是GetStaticMethodID( cls, "add", "(II)I")方法的第三个参数。GetStaticMethodID表示调用static方法,GetMethodID调用普通方法。下面就是传入参数,打出结果。 


在看jni.h的时候我们注意到有 CallStaticXXXMethod() 和 CallXXXMethod() 之类的方法。这些方法分别代表调用静态方法和成员方法,用方法的返回类型(例如,Object、Boolean、Byte、Char、Int、Long 等等)代替变量 XXX。 


静态方法和普通方法不同之处就是普通方法必须要先实例化一个java对象,调用构造器的时候方法的名称为“<init>”。 



下面的代码就不用我再解释了,先是new一个实例出来,然后调用实例的方法。 



最后记得销毁jvm。 



代码解释完了,我们build下这个工程,生成c2java.exe。 



4、运行exe 



因为我们生成的exe需要调用jvm.dll初始化,为了使运行的exe不报错误,我们把%JAVA_HOME%/jre/bin/server也加进path目录。方便系统自动搜索jvm.dll。 


运行结果: 


 



最后补充:本实例并没有涉及到java的异常、java c/cpp的编码转换问题,对于异常问题,C里没有异常,请使用jni的异常处理函数。编码转换问题上篇已有介绍,此处略去。



if   Cannot open include file: 'jni.h': No such file or directory
if you have this problem with the jni there is one really simple way to solve it.
1.) go to your project properties
2.) navigate in the tree to "Configuration Properties->C/C++" then look at the first entry "Additional Include Directories"
3.) in there enter the path: "<JDK-Version-Path>\include";"<JDK-Version-Path>\include\win32"

以上还是有错误

将jvm.dll和msvcr100.dll拷贝至程序目录下

在程序上下添加:

HINSTANCE hInstance = ::LoadLibraryA("C:\\Program Files\\Java\\jdk1.7.0_01\\jre\\bin\\server\\jvm.dll");
::FreeLibrary(hInstance);