Determining where jvm.dll is + extensive CPU usage
Hi,
I am trying to create a JNI wrapper for my java application. I have reached the stage where I can launch the program, providing I have the path to jvm.dll in my path variable.
I was wondering if there was any way to determine this path at runtime, seeming as it is highly unlikely anyone using this program would have it pre-set. I was thinking I could use run a command from within the program to set the path variable temporarily, however how would I determine where their javavm was installed?
Is there no way of shipping the dll with the program?
Also when running my java program through the JNI wrapper it uses about 85 - 90% of my CPU whereas when running it w/o the cpu usage is nominal (about 2 - 10%)
Why is this?
[764 byte] By [
bavardagea] at [2007-11-26 15:02:39]

# 1
Try the tool for MS Visual Studio 6.0 at http://www.simtel.net/product.php[id]93174[SiteID]simtel.netThere you will find other tools related (including JNI for .NET) for MS VS 7.1, 8.0.
# 2
> I was wondering if there was any way to determine this path at runtime
On Windows you read the registry database for this information.
Specifically you read the value of the string CurrentVersion
from the key HKEY_LOCAL_MACHINE/SOFTWARE/JavaSoft/Java Runtime Environment.
Then you use that value to read the value of the string RuntimeLib
from the key HKEY_LOCAL_MACHINE/SOFTWARE/JavaSoft/Java Runtime Environment/{CurrentVersion value}.
This value gives you the absolute path of the jvm.dll file.
> Also when running my java program through the JNI wrapper it uses about 85 - 90% of my CPU
> whereas when running it w/o the cpu usage is nominal (about 2 - 10%)
There is something wrong in your JNI code then.
It's impossible to tell what it is without seeing your code though.
Regards
# 3
What you wrote is only for SUN JDK1.3.x and later. But what about Registry info for SUN JDK1.1.x, JDK1.2.x ?Where registered IBM JDK 1.2.x-1.4.x. ?If I have more than one JDK update on my computer?
# 4
> What you wrote is only for SUN JDK1.3.x and later.
It's not the JDKs but the JREs.
Anyway it seems "reasonable" for a simple answer to assume the OP wants a JRE 1.3+.
My point being that the registry database is the place to look for the jvm.dll path on Windows.
> But what about Registry info for SUN JDK1.1.x, JDK1.2.x ?
Maybe that's not the OP's problem to create Java apps targeting versions 1.1 or 1.2 ?
> Where registered IBM JDK 1.2.x-1.4.x. ?
For IBM JREs 1.2+ it's the same principle but with HKEY_LOCAL_MACHINE/SOFTWARE/IBM/Java2 Runtime Environment instead.
> If I have more than one JDK update on my computer?
Depends on what you want to do with multiple JREs installed.
First you can search for current version but if your Java app has a mandatory min version
that must be greater than the current version found then you could search the keys for max version to see if it fits to use.
If you have another solution that does not involve a third party lib or app unless it is open-source and free
then by all means please share it with us.
Regards
# 5
> Maybe that's not the OP's problem to create Java apps
> targeting versions 1.1 or 1.2 ?
There are a number of products developed in JDK 1.1.x and customers use only JKD 1.1.x , 1.2.x, 1.3.x (I may not force them to install JKD other than Client has). For example, look at products by ORACLE they use JRE1.1.x. But in JRE 1.1.x there is "javai.dll" but not "jvm.dll", instead of "rt.jar" is "classes.zip". So the task is not such primitive as you guess. There are clients that use MSJ and this is JDK 1.1.4, "msjava.dll" instead of "jvm.dll".
My goal is to write JNI code that at runtime can use any Java Machine installed at Client's OS.
For example, we have developed a product that can at runtime connect to any Java application running (we do not know its sources), detect Java version and Provider (SUN, IBM, Microsoft), analyze and build its Component Model Map and expose it as COM interface to another process. Which can drive the Java application (read/write data to/from it, simulate User's actions, get notifications from components selected, etc.).
For this I developed Object-Oriented JNI SDK for C++, MCpp, J#, C#, VB that does not depend of JDK/JRE installed and Java Provider at Client's OS.
# 6
Still I'll bet that your product uses the registry database to read the appropriate information about the various JREs installed, right?
That is what I've been doing since 1.0 on Windows machines anyway.
Although it is not a trivial task to get the information for all flavors/versions of Java installed on a machine (and I never said it was trivial), again, maybe that is not the OPs probem.
Maybe the OP wants an answer for relatively new Java versions only.
Don't take it the wrong way but maybe it would be a good idea to also share a bit of your knowledge here instead of just advertising your product (which is a fine product I'm sure).
Regards
# 7
And if the user's computer doesn't have a java?
I reached the conclusion long ago that the only sane way to ship and install a java application is with a private jre. When it's installed (copied) you know exactly where and what it is, and you can be confident that any other java work done by the user will not stumble over the private java.
# 8
Sorry for the lack of response... Been doing other things and forgot about this post...
>First you can search for current version but if your Java >app has a mandatory min version
>that must be greater than the current version found then >you could search the keys for max version to see if it fits >to use.
My program requires j1.6 though could be downgraded to req 1.5 with the removal of 1 class
>]On Windows you read the registry database for this >information.
>Specifically you read the value of the string >CurrentVersion from the key >HKEY_LOCAL_MACHINE/SOFTWARE/JavaSoft/Java >Runtime Environment.
>Then you use that value to read the value of the string >RuntimeLib
>from the key >HKEY_LOCAL_MACHINE/SOFTWARE/JavaSoft/Java >Runtime Environment/{CurrentVersion value}.
>This value gives you the absolute path of the jvm.dll file.
sorry I probably didn't explain how new I am at JNI. All I have is minimal C++ experience (command line hello world apps and the like), and amateur experimentation with java (only 15, not out of secondary education yet.) How does one go about reading the registry using C/C++, (although I'm sure I could find some documentation somewhere on the net.)
>Depends on what you want to do with multiple JREs >installed.
get the newest one :)
Basic wrapper code I am using at the moment...: (all I want to do is execute my java app from a .exe file rather than an executable jar)
As you can probably see.. is just a bodge of an example from the internet.
Currently my program searches for jvm.dll from the PATH variable.
#include <stdio.h>
#include <jni.h>
void invoke_class(JNIEnv* env) {
jclass helloWorldClass;
jmethodID mainMethod;
jobjectArray applicationArgs;
jstring applicationArg0;
helloWorldClass = (*env)->FindClass(env, "be/bavardage/vocab/VocabGUI");
mainMethod = (*env)->GetStaticMethodID(env, helloWorldClass, "main", "([Ljava/lang/String;)V");
applicationArgs = (*env)->NewObjectArray(env, 1, (*env)->FindClass(env, "java/lang/String"), NULL);
applicationArg0 = (*env)->NewStringUTF(env, "From-C-program");
(*env)->SetObjectArrayElement(env, applicationArgs, 0, applicationArg0);
(*env)->CallStaticVoidMethod(env, helloWorldClass, mainMethod, applicationArgs);
}
int main(int argc, char **argv) {
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options[1];
/* There is a new JNI_VERSION_1_4, but it doesn't add anything for the purposes of our example. */
args.version = JNI_VERSION_1_6;
args.nOptions = 1;
//options[0].optionString = "-Djava.class.path=c:\\package\\";
options[0].optionString = "-Djava.class.path=vocab.jar";
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
JNI_CreateJavaVM(&jvm, (void **)&env, &args);
env;
invoke_class( env );
while (!(*env)->ExceptionCheck( env )) {
//nothing
}
(*env)->ExceptionCheck( env );
(*env)->ExceptionDescribe( env );
(*jvm)->DestroyJavaVM( jvm );
}
Message was edited by:
bavardage - used [quote] tags...
Message was edited by:
bavardage
# 9
The following are modifications and additions to your code (works with Sun JRE 1.4+).
It reads the jvm.dll path from the registry database and loads dynamically the library without the need for it to be located in the execution Path.#include <windows.h>
#include <jni.h>
typedef jint (JNICALL JNI_CreateJavaVM_t)(JavaVM ** pJvm, JNIEnv ** pEnv, void * vmArgs);
#define JRE_KEY "SOFTWARE\\JavaSoft\\Java Runtime Environment"
#define CURVER_STR"CurrentVersion"
#define RUNLIB_STR"RuntimeLib"
static
int readStringFromRegistry(HKEY key, const char * name, char * buf, DWORD bufsize) {
DWORD type, size;
if ((RegQueryValueEx(key, name, NULL, &type, NULL, &size) == ERROR_SUCCESS)
&& (type == REG_SZ)
&& (size < bufsize)) {
if (RegQueryValueEx(key, name, NULL, NULL, buf, &size) == ERROR_SUCCESS)
return 0;
}
return -1;
}
static
int readJvmPathFromRegistry(char * buf, int bufsize) {
HKEY key, subkey;
char version[MAX_PATH];
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, JRE_KEY, 0, KEY_READ, &key) != ERROR_SUCCESS)
return -1;
if (readStringFromRegistry(key, CURVER_STR, version, sizeof(version)) != 0) {
RegCloseKey(key);
return -2;
}
if (RegOpenKeyEx(key, version, 0, KEY_READ, &subkey) != ERROR_SUCCESS) {
RegCloseKey(key);
return -3;
}
if (readStringFromRegistry(subkey, RUNLIB_STR, buf, bufsize) != 0) {
RegCloseKey(subkey);
RegCloseKey(key);
return -4;
}
RegCloseKey(subkey);
RegCloseKey(key);
return 0;
}
static
void invoke_class(JNIEnv* env) {
...
}
int main(int argc, char **argv) {
char jvmPath[MAX_PATH];
HINSTANCE hLib;
JNI_CreateJavaVM_t * JNI_CreateJavaVM_f;
JavaVM * jvm;
JNIEnv * env;
JavaVMInitArgs args;
JavaVMOption options[1];
if (readJvmPathFromRegistry(jvmPath, sizeof(jvmPath)) != 0)
return -1;
hLib = LoadLibrary(jvmPath);
if (hLib == NULL)
return -2;
JNI_CreateJavaVM_f = (JNI_CreateJavaVM_t *)GetProcAddress(hLib, "JNI_CreateJavaVM");
if (JNI_CreateJavaVM_f == NULL) {
FreeLibrary(hLib);
return -3;
}
args.version = JNI_VERSION_1_4;
args.nOptions = 1;
options[0].optionString = "-Djava.class.path=vocab.jar";
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
if (JNI_CreateJavaVM_f(&jvm, &env, &args) != JNI_OK) {
FreeLibrary(hLib);
return -4;
}
invoke_class(env);
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
(*jvm)->DetachCurrentThread(jvm);
(*jvm)->DestroyJavaVM(jvm);
FreeLibrary(hLib);
return 0;
}
Regards
# 10
Thank you so much for your assistance, you have been a great help. Wish I was that proficient at c...The code works perfectly, and no longer takes massive amounts of CPU.