Name: mm8553 Date: 05/12/99
I wrote a C program which creates a JVM using the JNI invocation
interfaces. This program fails with the HotSpot jvm because the
HotSpot jvm doesn't support jvm creation options (specified to
JNI_CreateJavaVM() in the array of JavaVMOption structs) which
are documented as being supported by all JVMs. Specifically,
the HotSpot jvm doesn't support "vfprintf", "exit", or "abort".
The document docs/guide/jni/jni-12.html says these must be
supported. My program depends on it. As an aside, the HotSpot
jvm returns JNI_EINVAL from JNI_CreateJavaVM() for this
situation, but the doc says that JNI_ERR will be returned
(though JNI_EINVAL seems more sensible to me).
Although you probably don't need it to diagnose the problem,
the following C program demonstrates the failure. The JVM
outputs this message to standard error when you run it.
Unrecognized option: vfprintf
-------------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <jni.h>
#define WIN32_LEAN_AND_MEAN
#define STRICT
#include <windows.h>
void describeError(const char *fcn, long errcode);
#define describeLastError(x) describeError(x, GetLastError())
struct JavaRuntimeInfo {
jint (JNICALL *CreateJavaVM)(JavaVM **pvm, void **penv, void *args);
};
static int LoadJavaRuntime(struct JavaRuntimeInfo *info);
static jint JNICALL jvm_output(FILE *stream, const char *format, va_list arg);
static JavaVM *jvm; // Describes a Java virtual machine
int main(int argc, char **argv) {
struct JavaRuntimeInfo javaRuntimeInfo;
JavaVMInitArgs vm_args; // For initializing the Java VM
JavaVMOption *options = (JavaVMOption *) malloc(2 * sizeof(JavaVMOption));
int optcnt = 0;
char *cp, *tcp;
size_t classlen;
JNIEnv *env;
jint cr;
/* Pick and load a Java runtime DLL */
LoadJavaRuntime(&javaRuntimeInfo);
if (!options) {
fprintf(stderr, "Unable to acquire storage for JVM initialization options\n");
return 1;
}
/* Build class path to use */
cp = getenv("CLASSPATH");
classlen = sizeof "-Djava.class.path=" + (cp ? strlen(cp) : 1);
tcp = (char *) malloc(classlen);
if (!tcp) {
fprintf(stderr, "Unable to acquire storage for CLASSPATH\n");
return 1;
}
sprintf(tcp, "-Djava.class.path=%s", cp ? cp : ".");
options[optcnt++].optionString = tcp;
printf("Setting %s\n", tcp);
#ifndef SUPPRESS_HOTSPOT_BUG
/* Trap line-mode output from JVM */
options[optcnt].optionString = "vfprintf";
options[optcnt++].extraInfo = jvm_output;
printf("Redirecting JVM output.\n");
#endif
/* Initialize fields in startup struct */
vm_args.version = JNI_VERSION_1_2; /* Initialize version field */
vm_args.options = options;
vm_args.nOptions = optcnt;
vm_args.ignoreUnrecognized = JNI_FALSE;
printf("Creating Java VM\n");
cr = javaRuntimeInfo.CreateJavaVM(&jvm, (void **) &env, &vm_args);
if (cr) {
printf("Call to JNI_CreateJavaVM() failed with result value %ld.\n", (long) cr);
return 1;
}
printf("Created Java VM successfully\n");
/* Exit without doing anything useful */
return 0;
}
static char *readStringRegValue(HKEY keyhandle, const char *valueName) {
unsigned char *retvalue;
DWORD valuelen;
DWORD valueType;
long result = RegQueryValueEx(keyhandle, valueName, NULL, &valueType,
NULL, &valuelen);
if (result != ERROR_SUCCESS) describeError("RegQueryValueEx", result);
if (valueType != REG_SZ && valueType != REG_EXPAND_SZ) {
fprintf(stderr, "Unexpected response from RegQueryValueEx(): "
"Value's type is %ld\n", (long) valueType);
exit(201);
}
retvalue = (unsigned char *) malloc(valuelen);
if (!retvalue) {
fprintf(stderr, "Unable to acquire storage to read registry\n");
exit(201);
}
result = RegQueryValueEx(keyhandle, valueName, NULL, &valueType,
retvalue, &valuelen);
if (result != ERROR_SUCCESS) describeError("RegQueryValueEx", result);
return (char *) retvalue;
}
/* Locate the jvm dll to use. Look for hotspot, then classic. */
#define JRE_KEY "Software\\JavaSoft\\Java Runtime Environment"
#define HOTSPOT_PATH "\\bin\\hotspot\\jvm.dll"
#define CLASSIC_PATH "\\bin\\classic\\jvm.dll"
static int LoadJavaRuntime(struct JavaRuntimeInfo *info) {
HKEY key, subkey;
char *version, *homedir, *runtimedll;
char workarea[FILENAME_MAX];
long result;
HINSTANCE dllHandle;
struct stat st;
/* Find the name of the DLL for the current version of the JRE */
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, JRE_KEY, 0, KEY_QUERY_VALUE,
&key);
if (result != ERROR_SUCCESS) describeError("RegOpenKeyEx", result);
version = readStringRegValue(key, "CurrentVersion");
result = RegOpenKeyEx(key, version, 0, KEY_QUERY_VALUE, &subkey);
if (result != ERROR_SUCCESS) describeError("RegOpenKeyEx", result);
RegCloseKey(key);
free(version);
/* Initialize our dll path to the one named in the registry. We fall */
/* back on this value if our later checks fail. */
runtimedll = readStringRegValue(subkey, "RuntimeLib");
homedir = readStringRegValue(subkey, "JavaHome");
RegCloseKey(subkey);
/* Look for the hotspot jvm first. If not found, try the classic jvm. */
if (strlen(homedir) + sizeof HOTSPOT_PATH <= sizeof workarea) {
sprintf(workarea, "%s" HOTSPOT_PATH, homedir);
if (!stat(workarea, &st)) {
runtimedll = workarea; /* This is the dll to use */
} else {
/* Check for classic jvm */
if (strlen(homedir) + sizeof CLASSIC_PATH <= sizeof workarea) {
sprintf(workarea, "%s" CLASSIC_PATH, homedir);
if (!stat(workarea, &st)) {
runtimedll = workarea; /* This is the dll to use */
}
}
}
}
printf("Using JVM dll: %s\n", runtimedll);
dllHandle = LoadLibrary(runtimedll);
if (!dllHandle) describeLastError("LoadLibrary");
info->CreateJavaVM =
(jint (JNICALL *)(JavaVM **, void **, void *))
GetProcAddress(dllHandle, "JNI_CreateJavaVM");
if (!info->CreateJavaVM) describeLastError("GetProcAddress");
return 0;
}
static FILE *errors = NULL;
static jint JNICALL jvm_output(FILE *stream, const char *format,
va_list arg) {
if (!errors) {
errors = fopen("ErrorsFromJvm", "w");
if (!errors) {perror("Error opening jvm output file"); exit(10);}
}
return vfprintf(errors, format, arg);
}
static void describeError(const char *fcn, long errcode) {
char *msgbuffer;
DWORD rc = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, errcode, 0, (char *) &msgbuffer, 0, NULL);
if (!rc) {
fprintf(stderr, "Received error code %ld from FormatMessage() while"
" trying\nto format message for error code %ld, from"
" function %s()\n", GetLastError(), errcode, fcn);
return;
}
fprintf(stderr, "Received error code %ld from function %s(): %s",
errcode, fcn, msgbuffer);
LocalFree(msgbuffer);
exit(101);
}
(Review ID: 57737)
======================================================================