| |
"Creating a Custom Launcher"
Vol. 7, Issue 9, p. 48
Listing 1: Typical Windows launcher for a 1.2 or later VM
#include <windows.h>
#include <jni.h>
#include <string>
using namespace std;
void vShowError(string sErrorMessage);
void vShowLastError(string sErrorMessage);
void vDestroyVM(JNIEnv *env, JavaVM *jvm);
void vAddOption(string& sName);
JavaVMOption* vm_options;
int mctOptions = 0;
int mctOptionCapacity = 0;
boolean GetApplicationHome(char *buf, jint sz);
typedef jint (CALLBACK *CreateJavaVM)(JavaVM
**pvm, JNIEnv **penv, void *args);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, PSTR szCmdLine,
int iCmdShow) {
JNIEnv *env;
JavaVM *jvm;
jint jintVMStartupReturnValue;
jclass jclassStartup;
jmethodID midStartup;
// Path Determination
// --- application home
char home[2000];
if (!GetApplicationHome(home, sizeof(home))) {
vShowError("Unable to determine \
application home.");
return 0;
}
string sAppHome(home);
string sOption_AppHome = "-Dapplication.home="
+ sAppHome;
string sJREPath = sAppHome + "\\jre";
// --- VM Path
string sRuntimePath = sJREPath +
"\\bin\\classic\\"; // must contain jvm.dll
string sJVMpath = sRuntimePath + "jvm.dll";
// --- boot path
string sBootPath = sJREPath + "\\lib";
string sOption_BootPath =
"-Dsun.boot.class.path=" + sBootPath;
// --- class path
string sClassPath = sAppHome + "\\classes";
string sOption_ClassPath =
"-Djava.class.path=" + sClassPath;
// setup VM options
// vAddOption(string("-verbose"));
vAddOption(sOption_ClassPath);
vAddOption(sOption_AppHome);
// initialize args
JavaVMInitArgs vm_args;
vm_args.version = 0x00010002;
vm_args.options = vm_options;
vm_args.nOptions = mctOptions;
vm_args.ignoreUnrecognized = JNI_TRUE;
// load jvm library
HINSTANCE hJVM = LoadLibrary(sJVMpath.c_str());
if( hJVM == NULL ){
vShowLastError("Failed to load JVM from "
+ sJVMpath);
return 0;
}
// try to start 1.2/3/4 VM
// uses handle above to locate entry point
CreateJavaVM lpfnCreateJavaVM = (CreateJavaVM)
GetProcAddress(hJVM, "JNI_CreateJavaVM");
jintVMStartupReturnValue = (*lpfnCreateJavaVM)
(&jvm, &env, &vm_args);
// test for success
if (jintVMStartupReturnValue < 0) {
string sErrorMessage = "Unable to create VM.";
vShowError(sErrorMessage);
vDestroyVM(env, jvm);
return 0;
}
// find startup class
string sStartupClass = "javabunny/JavaBunny";
// notice dots are translated to slashes
jclassStartup =
env->FindClass(sStartupClass.c_str());
if (jclassStartup == NULL) {
string sErrorMessage =
"Unable to find startup class [" +
sStartupClass + "]";
vShowError(sErrorMessage);
vDestroyVM(env, jvm);
return 0;
}
// find startup method
string sStartupMethod_Identifier = "main";
string sStartupMethod_TypeDescriptor =
"([Ljava/lang/String;)V";
midStartup =
env->GetStaticMethodID(jclassStartup,
sStartupMethod_Identifier.c_str(),
sStartupMethod_TypeDescriptor.c_str());
if (midStartup == NULL) {
string sErrorMessage =
"Unable to find startup method ["
+ sStartupClass + "."
+ sStartupMethod_Identifier
+ "] with type descriptor [" +
sStartupMethod_TypeDescriptor + "]";
vShowError(sErrorMessage);
vDestroyVM(env, jvm);
return 0;
}
// create array of args to startup method
jstring jstringExampleArg;
jclass jclassString;
jobjectArray jobjectArray_args;
jstringExampleArg =
env->NewStringUTF("example string");
if (jstringExampleArg == NULL){
vDestroyVM(env, jvm);
return 0;
}
jclassString =
env->FindClass("java/lang/String");
jobjectArray_args =
env->NewObjectArray(1, jclassString,
jstringExampleArg);
if (jobjectArray_args == NULL){
vDestroyVM(env, jvm);
return 0;
}
// call the startup method -
// this starts the Java program
env->CallStaticVoidMethod(jclassStartup,
midStartup, jobjectArray_args);
// attempt to detach main thread before exiting
if (jvm->DetachCurrentThread() != 0) {
vShowError("Could not detach main thread.\n");
}
// this call will hang as long as there are
// non-daemon threads remaining
jvm->DestroyJavaVM();
return 0;
}
void vDestroyVM(JNIEnv *env, JavaVM *jvm)
{
if (env->ExceptionOccurred()) {
env->ExceptionDescribe();
}
jvm->DestroyJavaVM();
}
void vShowError(string sError) {
MessageBox(NULL, sError.c_str(),
"Model App Error", MB_OK);
}
/* Shows an error message in an OK box with the
system GetLastError appended in brackets */
void vShowLastError(string sLocalError) {
LPVOID lpSystemMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpSystemMsgBuf, 0, NULL );
string sSystemError =
string((LPTSTR)lpSystemMsgBuf);
vShowError(sLocalError +
" [" + sSystemError + "]");
}
void vAddOption(string& sValue) {
mctOptions++;
if (mctOptions >= mctOptionCapacity) {
if (mctOptionCapacity == 0) {
mctOptionCapacity = 3;
vm_options =
(JavaVMOption*)malloc(mctOptionCapacity *
sizeof(JavaVMOption));
} else {
JavaVMOption *tmp;
mctOptionCapacity *= 2;
tmp =
(JavaVMOption*)malloc(mctOptionCapacity *
sizeof(JavaVMOption));
memcpy(tmp, vm_options, (mctOptions-1) *
sizeof(JavaVMOption));
free(vm_options);
vm_options = tmp;
}
}
vm_options[mctOptions-1].optionString =
(char*)sValue.c_str();
}
/* If buffer is "c:\app\bin\java",
* then put "c:\app" into buf. */
jboolean GetApplicationHome(char *buf, jint sz) {
char *cp;
GetModuleFileName(0, buf, sz);
*strrchr(buf, '\\') = '\0';
if ((cp = strrchr(buf, '\\')) == 0) {
// This happens if the application is in a
// drive root, and there is no bin directory.
buf[0] = '\0';
return JNI_FALSE;
}
return JNI_TRUE;
}
|
|