This discussion is archived
2 Replies Latest reply: Jul 14, 2011 4:18 AM by 875447 RSS

JNI Version Wrong? Error Code = JNI_EVERSION

875447 Newbie
Currently Being Moderated
Hi people,

I have a jar file and I want to call those jar-file-methods from my C++ Project. B'coz I never have used JNI, I would like to create a simple example to see how is that running:

[JAVA]
public class HelloFunc {
     
     static {
          System.mapLibraryName("HelloFunc");
     }
     
     public static void main(String[] args) {
          if (args.length > 0) System.out.println("Hello World " + args[0]);
          else System.out.println("Hello World /wo Args!");
     }
}
[JAVA]
I exported that Java programm above with Eclipse as an executable jar file, which is used in the project below. In his case I want to call the main-Method from my C++ project:

[CPP]
#include <jni.h>
#include "JNI_IF.h"

// C:\Program Files\Java\jdk1.6.0_26\lib
#pragma comment (lib,"C:\\Program Files\\Java\\jdk1.6.0_26\\lib\\jvm.lib")

JNI_IF::JNI_IF(char* JVMOptionString)
{
     JavaVMInitArgs vm_args;
     JavaVMOption options[1];
     options[0].optionString = JVMOptionString;
     vm_args.options = options;
     vm_args.nOptions = 1;
     vm_args.version = JNI_VERSION_1_6;
     vm_args.ignoreUnrecognized = JNI_FALSE;
}

void JNI_IF::setClassName(char* className)
{  
     result = JNI_CreateJavaVM( &jvm,(void **)&env, &vm_args);

     switch(result)
     {
          case JNI_ERR:
               printf("Unknown Error invoking the JVM\n");
               return;
          case JNI_EDETACHED:
               printf("Thread detached from the JVM\n");
               return;
          case JNI_EVERSION:
               printf("JNI version error\n");
               return;
          case JNI_ENOMEM:
               printf("Not enough memory the JVM\n");
               return;
          case JNI_EEXIST:
               printf("JVM already created\n");
               return;
          case JNI_EINVAL:
               printf("Invalid arguments\n");
               return;
          case JNI_OK:
               printf("JVM created --> Ready ...\n");
     }

     cls = env->FindClass(className);
     if( cls == NULL ) {
          printf("can't find class %s\n", className);
          return;
     }
     env->ExceptionClear();
}

void JNI_IF::setMethodName(char* methodName)
{
     mid = env->GetStaticMethodID(cls, methodName, "([Ljava/lang/String;)V");
     if (mid != NULL){
          env->CallStaticVoidMethod(cls,mid,"70");
     }
}

int main()
{
     JNI_IF JNIInterfaceObj("-Djava.class.path=M:\\Eigene Dateien\\Visual Studio 2008\\Projects\\JNI_IF\\JNI_IF;M:\\Eigene Dateien\\Visual Studio 2008\\Projects\\JNI_IF\\JNI_IF\\hello.jar");
     JNIInterfaceObj.setClassName("HelloFunc");
     JNIInterfaceObj.setMethodName("main");
     return 0;
}
[CPP]

And my corresponding header:
[HEADER]
#ifndef JNI_IF_H
#define JNI_IF_H
#include <jni.h>

class JNI_IF {
public:
     JNI_IF(char* JVMOptionString);
     void setMethodName(char* methodName);
     void setClassName(char* className);

private:
     JavaVMInitArgs vm_args;
     JavaVM *jvm;
     JNIEnv *env;
     //JNINativeInterface *env;
     long result;
     jmethodID mid;
     jfieldID fid;
     jobject jobj;
     jclass cls;
     int asize;
     char  JVMOptionString[20];
     char  className[20];
     char  methodName[20];
     JavaVMOption options[1];
}; 
#endif
[HEADER]

According to my debugger, I always got a JNI_EVERSION error --> so the JNI_CreateJavaVM() fails. Hows that be? I tried every versions JNI_VERSION_1_1, JNI_VERSION_1_2, JNI_VERSION_1_4 and JNI_VERSION_1_6. All the same error.

Windows XP Prof. SP 3, Visual Studio 2008, JDK 1.6.0_26. I linked the lib statically as you can see and the jvm.dll is in my projects debug folder.
I can compile and start the programm, but as I said, I got that error code.

I appreciate every hints and solutions, thank you for your patience.

Cheers

Edited by: 872444 on 14.07.2011 01:03

Edited by: EJP on 8/09/2011 18:38: code tags
  • 1. Re: JNI Version Wrong? Error Code = JNI_EVERSION
    EJP Guru
    Currently Being Moderated
    There are several major problems with this code.
    JNI_IF::JNI_IF(char* JVMOptionString)
    {
         JavaVMInitArgs vm_args;
         JavaVMOption options[1];
         options[0].optionString = JVMOptionString;
         vm_args.options = options;
         vm_args.nOptions = 1;
         vm_args.version = JNI_VERSION_1_6;
         vm_args.ignoreUnrecognized = JNI_FALSE;
    }
    So I assume vm_args is a class member. However you are setting vm_args.options to the address of a variable that will disappear as soon as this constructor exits. This is almost certainly the cause of your immediate problem, and if it isn't it will certainly cause problems further down the track. I would move most of code from setClassName() into here to address that.
    void JNI_IF::setClassName(char* className)

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

         switch(result)
         {
              case JNI_ERR:
                   printf("Unknown Error invoking the JVM\n");
                   return;
              case JNI_EDETACHED:
                   printf("Thread detached from the JVM\n");
                   return;
              case JNI_EVERSION:
                   printf("JNI version error\n");
                   return;
              case JNI_ENOMEM:
                   printf("Not enough memory the JVM\n");
                   return;
              case JNI_EEXIST:
                   printf("JVM already created\n");
                   return;
              case JNI_EINVAL:
                   printf("Invalid arguments\n");
                   return;
              case JNI_OK:
                   printf("JVM created --> Ready ...\n");
         }
    All that should be in the constructor.
         cls = env->FindClass(className);
    So it appears that 'cls' is also a member.
         if( cls == NULL ) {
              printf("can't find class %s\n", className);
              return;
         }
    If 'cls' was null there was an exception, and you should print it rather than making up your own message. You are losing information.
         env->ExceptionClear();
    Conversely if 'cls' isn't null there was no exception so there is nothing to clear here.
    void JNI_IF::setMethodName(char* methodName)
    There's not much point in making this a separate method. I would have one setEntryPoint() method that takes the classname and the method name. However as the method name has to be 'main' there's not much point in making it a parameter.
         mid = env->GetStaticMethodID(cls, methodName, "([Ljava/lang/String;)V");
    And here for example you are using a methodName parameter but a hardwired argument-list. So again there wasn't much point in the methodName parameter.
         if (mid != NULL){
              env->CallStaticVoidMethod(cls,mid,"70");
    ... else you should print something ... an exception. Otherwise you are again losing information. The program does nothing and silently exits. Not very informative. And this proves that the method is poorly named. You aren't just setting a method name, you are +calling+ it. I would say the method should be called run(), with no arguments.
  • 2. Re: JNI Version Wrong? Error Code = JNI_EVERSION
    875447 Newbie
    Currently Being Moderated
    Thank you very much. That was right, I just overlooked some faults. I removed those double member definitions. And the version error was gone.

    Then I only had to remove the jvm.dll from the debug folder; the jvm.dll must remain in its original folder. Just link that path to the environment &PATH&.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points