导读:
   简 介
  你遇到JNI和Cygwin的问题吗?你用Windoes下的JVM不能加载Cygwin下创建的库文件吗?这篇文章将帮助你通过创建JVM启动器来解决这个问题。我假设你对JNI有一个基本的理解。
   关于Cygwin
  Cygwin是一个为Windows平台开发的类Linux环境。它包含两部分:
  1.一个DLL(cygwin1.dll)。它作为Linux API仿真层提供了实质的Linux API功能。
  2.Linux风格的工具收集器。使用Cygwin,在Linux下的编译的程序经常几乎不用改变的被交叉变为为win32程序。它也能够帮助在Windows下使用Linux的库函数。
   JNI和Cygwin
  你试过从java中加载Cygwin jni dll吗?你可能会看到你的应用程序在System.loadLibrary().期间挂起了。原因是在Cygwin下Build的库要依赖cygwin1.dll。如果没有Cygwin使用的进程在运行,那么动态加载依赖于Cygwin(在加载时)的Dll将导致这个进程的死锁。因此我们需要Cygwin进程来启动JVM。这就简单了........!我们用C语言创建一个启动器然后在Cygwin下编译连接。Cygwin的 Java Invocation API 工作并允许JVM被启动。
   怎样创建(启动)JVM
  JDK或JRE中标准的启动器命令(java 或 javaw.exe)就是一个用java虚拟机(JVM)连接的C程序。启动器解释命令行参数加载虚拟机,然后通过invocationg接口运行java应用程序。JVM将来就会成为一个叫做jvm.dll的动态连接库。
  在进一步深入之前,让我们来讨论几个创建JVM会用到的结构体和函数
   JavaVMInitArgs
  java虚拟机的参数,它被定义在jni.h中 如下:
  typedef struct JavaVMInitArgs {
  /*JVM Version .It must be JNI_VERSION_1_2 or JNI_VERSION_1_4 or JVM will
  interpret pointer as a JDK1_1InitArgs*/
  jint version;
  /*number of JVM options*/
  jint nOptions;
  JavaVMOption *options;
  /*see definition of JavaVMOption below*/
  /*JVM option status. if JNI_TRUE, ignore options VM does not understand
  otherwise return JNI_ERR if there are any unrecognized options*/
  jboolean ignoreUnrecognized;} JavaVMInitArgs;
  /*Definition of JavaVMOption*/
  typedef struct JavaVMOption {
  char *optionString;
  /*a string containing the argument*/
  /*extra info to the JVM.Not important.*/
  void *extraInfo;} JavaVMOption;
  JNI_CreateJavaVM
  jint JNI_CreateJavaVM(JavaVM **p_vm, JNIEnv **p_env, void *vm_args);
  第一个参数是指向javaVM指针的指针。javaVM结构体能被用来绑定和分离来往于虚拟机的本地线程,也用来销毁这个虚拟机(从JDK1.4开始销毁虚拟机的方式不被支持了,DestroyJavaVM将一直等待直到除了当前线程还有所有用户线程都死亡之后才返回一个错误号)。第二个参数是一个指向JNIEnv指针的指针。JNIEnv结构体是JNI编程主要的做粗重工作的结构体。粗糙的讲,JNIEnv结构体与一个具体的java线程相对应,JNIEnv结构体由JNI_CreateJavaVM()返回,因此它代表了虚拟机的主线程。第三个参数是一个无类型指针,它包含虚拟机的参数。下面是一个创建虚拟机实例的代码:
  JavaVMInitArgs vm_args;
  JavaVMOption options[4];
  /* disable JIT */
  
  options[0].optionString ="-Djava.compiler=NONE";
  /* user classes */
  options[1].optionString = "-Djava.class.path=c://myclasses";
  /* native lib path */
  options[2].optionString = "-Djava.library.path=c://mylibs";
  options[3].optionString = "-verbose:jni"; /* print JNI msgs */
  vm_args.version = JNI_VERSION_1_2;
  vm_args.options = options;
  vm_args.nOptions = 4;
  vm_args.ignoreUnrecognized = TRUE;
  //Pointer to the function JNI_CreateJavaVM
  typedef jint (JNICALL CreateJavaVM_t)(JavaVM **pvm, void **env, void *args);
  //Load the jvm dll (the jvm !)
  HINSTANCE hinst = LoadLibrary("jvm.dll")
  //Get the address of the function
  CreateJavaVM_t *pfnCreateJavaVM = GetProcAddress(hinst, "JNI_CreateJavaVM");
  //Create JVM
  Int iRetval = pfnCreateJavaVM((&vm, (void **)&env,
  &vm_args);
  //Error handling.
  if (res < 0) {
  ... /* error occurred
  }
   使用这个实例
  为了能够启动任意一个java程序,首先我们必须找到我们指定的类然后我们才能调用这个类的main()方法。我们也可以传递参数给我们将要启动java程序。下面的代码片断向我们展示了这些:
  //Find the class
  
  jclass jcJclass = psJNIEnv->FindClass(mainClassName);
  
  //Find the main method id
  
  jmethodID jmMainMethod = psJNIEnv-> GetStaticMethodID(jcJclass, "main", "([Ljava/lang/String;)V");
  
  //Call the main method.
  
  psJNIEnv->CallStaticVoidMethod(jcJclass, jmMainMethod, joApplicationArgs);
  使用代码
  这个启动器的代码主要是为了在eclipse中使用而写,现在它还只能处理基本JVM参数。
  怎样编译?
  ->打开 一个 cygwin shell
  ->运行编译器. (g++ cvm.cpp -o javaw)
  怎样使用这个启动器?
  *复制这个javaw.exe到你所使用的JRE的bin目录下(备份你原来的javaw.exe)。确信你在eclipse下使用了这个JRE
  *从Cygwin shell启动eclipse。如果你输入eclipse,不能启动,可能是因为PATH没有设置,你可以做如下设置
  export PATH=/cygdrive/c/tools/eclipse3.2/:$PATH
  *现在它能不能加载你的JNI 库,可能是因为PATH没有设置Close eclipse,通过export命令设置路径
  e.g: export PATH=/cygdrive/c/tutorial/jni_libs/:$PATH
  *从你设置了路径的shell中启动eclipse
  注意:这个启动器可能不能与所有的JRE/JDK版本工作,因为不同的版本对于JVM的参数是不同的。我用j2re1.4.2_06 做了测试,可以工作。
  http://www.codeproject.com/useritems/cvm/cvm_src.zip
  http://www.codeproject.com/useritems/cvm/cvm.zip

本文转自
http://www.zzju.net/java/48459.html
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐