4 Replies Latest reply: Jan 10, 2011 10:08 PM by 800119 RSS

    Launching an app requiring java.library.path

      Hi all,

      I'm trying to create a win32 wrapper exe to launch an application that requires native libraries - speficially an SWT app, if that matters. CreateJavaVM works, however, FindClass() always returns NULL when I try to load my class with the main() method.

      What's strange is that FindClass() can load other classes that don't contain references to SWT in my application fine. I've verified that it'll load classes for raw data structures fine, of course those don't have my main() method in it. I also verified that it can load, and run, a simple "Hello World"-style Swing application. This makes me believe I need to do something to load or point to the SWT DLL's to get things working.

      Any ideas? Something in the options when calling CreateJavaVM perhaps? Here's how I'm currently calling it, including a futile attempt to set java.library.path (fails both with and without that part). For now I'm just dropping the DLL's in a directory and pointing to that, but I see that SWT apps can load the DLL's embeddedin swt.jar, which of course I'd like to take advantage of if possible:
      JNIEnv *createVM(const TCHAR *installLoc)
           JNIEnv *env;
           JavaVMInitArgs args;
           JavaVMOption options[2];
           jint res;
           char classPath[MAX_PATH];
           char javaLibPath[MAX_PATH];
           if (-1==sprintf(classPath, "-Djava.class.path=%S\\%S;%S\\%s", installLoc, MAIN_JAR, installLoc, "swt.jar"))
                return NULL;
      #ifdef DEBUG
           MessageBoxA(NULL, classPath, "Classpath parameter:", MB_OK);
           sprintf(javaLibPath, "-Djava.library.path=%S\\native\\win32", installLoc);
      #ifdef DEBUG
           MessageBoxA(NULL, javaLibPath, "Library path parameter:", MB_OK);
           args.version = JNI_VERSION_1_4;
           args.nOptions = 2;
           options[0].optionString = classPath;
           options[1].optionString = javaLibPath;
           args.options = options;
           args.ignoreUnrecognized = JNI_FALSE;
           res = CreateJavaVM(&jvm, (void **)&env, &args);
           return env;
        • 1. Re: Launching an app requiring java.library.path
          When FindClass returns null it means an exception occurred. You need to get that exception and output the result.

          Actually you need to do error checks like that for any call that replicates java behavior (like running methods, setting values, etc). If you ignore error results and then fail to handle exceptions it can result in indeterminate behavior which can lead to a system exception (crash.)

          As to your specific error you will probably find that your shared path is incomplete. You probably need the window OS dirs.
          • 2. Re: Launching an app requiring java.library.path
            Thanks. I put some more debugging in by using the "vfprintf" option along with "-verbose:jni", and wrote all the info out to a file. I tried to capture the exception occurring at my FindClass call like so:
            clazz = (*env)->FindClass(env, "test/app/Main");
            if (clazz==NULL)
                 jthrowable exc = (*env)->ExceptionOccurred(env);
                 if (exc)
                      jboolean isCopy;
                      jclass exccls = (*env)->FindClass(env, "java/lang/Throwable");
                      jmethodID getMessage = (*env)->GetMethodID(env, exccls, "getMessage", "()Ljava/lang/String;");
                      jstring message = (*env)->CallObjectMethod(env, exc, getMessage);
                      if (message)
                           const char *utfMessage = (*env)->GetStringUTFChars(env, message, &isCopy);
                           MessageBoxA(NULL, utfMessage, "Exception message:", MB_OK|MB_ICONERROR);
                           (*env)->ReleaseStringUTFChars(env, message, utfMessage);
                 PRINT_ERROR(_T("Could not find the main class!"));
                 return FALSE;
            Unfortunately, it appears the thrown Exception has no message associated with it - in my JNI log all I get besides messages about registering/linking native methods in JDK classes is 'Exception in thread "main"' (no description text). I believe i verified this by using the commented-out section above; the "message" jstring always has a NULL value.

            How can I proceed with debugging this further?
            • 3. Re: Launching an app requiring java.library.path
              It is a java exception. You do the same thing as in java - print the stack trace.
              • 4. Re: Launching an app requiring java.library.path
                Thanks for the help jschell. Turned out to be user error, I was testing my starter executable with an old/incomplete jar file that was missing vital contents (*.properties files for ResourceBundles, for example). I updated the jar that the executable launched, and the application is launched.

                Taking your advice, I'm sure now to check each JNI call to ensure an exception isn't thrown. I'm learning the basics of the JNI API as I go, so this is good practice for me. All this legwork makes me happy that I usually work with much friendlier languages and libraries. :)