Javaコードをexeファイルにパッケージ化
Javaコードをexeファイルにパッケージ化するツールが多く、実行時にバッチファイルを作成したり、コマンドラインに長いclasspath情報を入力したりする必要がなく、ユーザーの使用に便利です.これも多くのビジネスソフトウェアでよく使われる方法です.
Javaコードをexeファイルにパッケージするには、一般的に2つのステップが必要です.
1.ローカルコードを作成し、仮想マシンを作成し、Main Classをロードして実行します.
2.Javaコードをjarファイルにパッケージ化し、ローカルコードexeファイルとマージします.
次のコードは、jvm.dllがロードされ、JNI_が呼び出されます.CreateJavaVMエクスポート関数Java仮想マシンを作成し、JNIEnvポインタを取得し、FindClassを呼び出してMain Classを検索し、GetStaticMethodIDメソッドを呼び出してmainメソッドを取得し、mainメソッドを実行します.コードは次のとおりです.
C:\>copy test.exe+test.jar test.exe
実は、Javaパッケージファイルをexeファイルの末尾に追加します.「ファイルのプロパティ」ダイアログ・ボックスが開き、「圧縮ファイル」プロパティ・ページが表示されます.老舗のJBuilder.exe開発ツールが作成したexeファイルは、次のように生成されます.
後述:Eclipse 3.2とEclipse 3.3を使用すると、タスクマネージャで両者の違いが表示されます.Eclipse 3.2は、まずEclipse.exeファイルを起動し、次にEclipse.exeからJavaw.exeファイルを起動して仮想マシンを作成します.
Eclipse 3.2は、タスクマネージャでEclipse.exeとjavaw.exeの2つのプロセスとして表示されます.
Eclipse 3.3タスクマネージャにEclipse.exeのプロセスとして表示されます.
以上から分かるように、Eclipse 3.2とEclipse 3.3は異なる仮想マシンロード方式を採用している.
Eclipse 3.2はサブプロセスを作成する方法でjavaw.exeを呼び出して起動し、windowsの下でCreateProcess方法を使用することができます.この方法は簡単です.具体的にはEclipseソースコードを参照してください.
Eclipse 3.3 java仮想マシンをロードするもう1つの方法は、jvmの動的ライブラリをロードし、動的ライブラリのインタフェースを介してこのプロセス内でjava仮想マシンを起動することです.本稿の冒頭で採用した第2の方法.
Javaコードをexeファイルにパッケージするには、一般的に2つのステップが必要です.
1.ローカルコードを作成し、仮想マシンを作成し、Main Classをロードして実行します.
2.Javaコードをjarファイルにパッケージ化し、ローカルコードexeファイルとマージします.
次のコードは、jvm.dllがロードされ、JNI_が呼び出されます.CreateJavaVMエクスポート関数Java仮想マシンを作成し、JNIEnvポインタを取得し、FindClassを呼び出してMain Classを検索し、GetStaticMethodIDメソッドを呼び出してmainメソッドを取得し、mainメソッドを実行します.コードは次のとおりです.
#include <windows.h>
#include <jni.h>
//#pragma comment( linker, "/subsystem:"console" /entry:"mainCRTStartup"" )
#pragma comment( linker, "/subsystem:"windows" /entry:"WinMainCRTStartup"" )
typedef jint (JNICALL *JNICREATEPROC)(JavaVM **, void **, void *);
bool setStream(JNIEnv *env, const char * pszFileName, const char * pszMethod);
// java
//bool main(int argc,char *argv[])
int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow)
... {
//jvm
const char szJvmPath[] = "d:\jdk1.5.0_07\jre\bin\server\jvm.dll";
//java , ,
int nOptionCount = 2;
JavaVMOption options[2];
options[1].optionString = "-Xmx256M";
// classpath
options[0].optionString = "-Djava.class.path=./Test.exe";
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_4;
vm_args.options = options;
vm_args.nOptions = nOptionCount;
vm_args.ignoreUnrecognized = JNI_TRUE;
// , / , test.JTest test/JTest
const char szStartClass[] = "com/primeton/test/TestClass";
// , main ,
const char szStartMethod[] = "main";
//
const char szStdoutFileName[] = "stdout.txt";
const char szStderrFileName[] = "stderr.txt";
//java
int nParamCount = 2;
const char *szParams[2] = ... {"arg1","arg2"};
// JVM 。
HINSTANCE jvmDll = LoadLibrary(szJvmPath);
if (jvmDll == NULL)
... {
printf(" JVM 。 %l", ::GetLastError());
return false ;
}
// JNI_CreateJavaVM 。
JNICREATEPROC jvmCreateProc = (JNICREATEPROC)GetProcAddress(jvmDll, "JNI_CreateJavaVM");
if (jvmCreateProc == NULL)
... {
FreeLibrary(jvmDll);
printf(" JNI_CreateJavaVM 。 %l", ::GetLastError());
return false ;
}
// JVM 。
JNIEnv *env;
JavaVM *jvm;
jint r = (jvmCreateProc)(&jvm, ( void **)&env, &vm_args);
if (r < 0 || jvm == NULL || env == NULL)
... {
FreeLibrary(jvmDll);
printf( " JVM 。 ");
return false ;
}
// stdout, stderr
if (!setStream(env, szStdoutFileName, "setOut"))
... {
printf(" stdout ");
return false ;
}
if (!setStream(env, szStderrFileName, "setErr"))
... {
printf(" stderr ");
return false ;
}
// 。
jclass serviceClass = env->FindClass(szStartClass);
if (env->ExceptionCheck() == JNI_TRUE || serviceClass == NULL)
... {
env->ExceptionDescribe();
env->ExceptionClear();
FreeLibrary(jvmDll);
printf(" 。 ");
return false ;
}
//
jmethodID mid = env->GetStaticMethodID(serviceClass, szStartMethod , "([Ljava/lang/String;)V");
if (env->ExceptionCheck() == JNI_TRUE || mid == NULL)
... {
env->ExceptionDescribe();
env->ExceptionClear();
FreeLibrary(jvmDll);
printf(" 。 ");
return false ;
}
// String 。
jclass stringClass = env->FindClass("java/lang/String");
if (env->ExceptionCheck() == JNI_TRUE || stringClass == NULL)
... {
env->ExceptionDescribe();
env->ExceptionClear();
FreeLibrary(jvmDll);
printf(" String 。 ");
return false ;
}
jstring jstr;
jobjectArray args = 0;
args = env->NewObjectArray(2, stringClass, 0);
for ( int i=0; i<nParamCount; i++)
... {
jstr = env->NewStringUTF(szParams[i]);
if (jstr == 0) ... {
printf(" String ");
if (env->ExceptionOccurred()) ... {
env->ExceptionDescribe();
env->ExceptionClear();
}
return false ;
}
env->SetObjectArrayElement(args, i, jstr);
if (env->ExceptionCheck() == JNI_TRUE)
... {
printf(" ");
if (env->ExceptionOccurred()) ... {
env->ExceptionDescribe();
env->ExceptionClear();
}
return false ;
}
}
// Java
//env->CallStaticVoidMethod(serviceClass, mid, parameterArray);
env->CallStaticVoidMethod(serviceClass, mid, args);
if (env->ExceptionCheck() == JNI_TRUE)
... {
env->ExceptionDescribe();
env->ExceptionClear();
FreeLibrary(jvmDll);
return false ;
}
MSG msg ;
while (GetMessage (&msg, NULL, 0, 0))
... {
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return true ;
}
//
bool setStream(JNIEnv *env, const char * pszFileName, const char * pszMethod)
... {
int pBufferSize = 1024;
char * pBuffer = new char [pBufferSize];
// 。
jstring pathString = env->NewStringUTF(pszFileName);
if (env->ExceptionCheck() == JNI_TRUE || pathString == NULL)
... {
env->ExceptionDescribe();
env->ExceptionClear();
printf(" 。 ");
return false ;
}
// FileOutputStream 。
jclass fileOutputStreamClass = env->FindClass("java/io/FileOutputStream");
if (env->ExceptionCheck() == JNI_TRUE || fileOutputStreamClass == NULL)
... {
env->ExceptionDescribe();
env->ExceptionClear();
printf(" FileOutputStream 。 ");
return false ;
}
// FileOutputStream 。
jmethodID fileOutputStreamConstructor = env->GetMethodID(fileOutputStreamClass, "<init>", "(Ljava/lang/String;)V");
if (env->ExceptionCheck() == JNI_TRUE || fileOutputStreamConstructor == NULL)
... {
env->ExceptionDescribe();
env->ExceptionClear();
printf(" FileOutputStream 。 ");
return false ;
}
// FileOutputStream 。
jobject fileOutputStream = env->NewObject(fileOutputStreamClass, fileOutputStreamConstructor, pathString);
if (env->ExceptionCheck() == JNI_TRUE || fileOutputStream == NULL)
... {
env->ExceptionDescribe();
env->ExceptionClear();
printf(" FileOutputStream 。 ");
return false ;
}
// PrintStream 。
jclass printStreamClass = env->FindClass("java/io/PrintStream");
if (env->ExceptionCheck() == JNI_TRUE || printStreamClass == NULL)
... {
env->ExceptionDescribe();
env->ExceptionClear();
printf(" PrintStream 。 ");
return false ;
}
// PrintStream 。
jmethodID printStreamConstructor = env->GetMethodID(printStreamClass, "<init>", "(Ljava/io/OutputStream;)V");
if (env->ExceptionCheck() == JNI_TRUE || printStreamConstructor == NULL)
... {
env->ExceptionDescribe();
env->ExceptionClear();
printf(" PrintStream 。 ");
return false ;
}
// PrintStream 。
jobject printStream = env->NewObject(printStreamClass, printStreamConstructor, fileOutputStream);
if (env->ExceptionCheck() == JNI_TRUE || printStream == NULL)
... {
env->ExceptionDescribe();
env->ExceptionClear();
printf(" PrintStream 。 ");
return false ;
}
// System 。
jclass systemClass = env->FindClass("java/lang/System");
if (env->ExceptionCheck() == JNI_TRUE || systemClass == NULL)
... {
env->ExceptionDescribe();
env->ExceptionClear();
printf( " System 。 ");
return false ;
}
// System 。
jmethodID setStreamMethod = env->GetStaticMethodID(systemClass, pszMethod, "(Ljava/io/PrintStream;)V");
if (env->ExceptionCheck() == JNI_TRUE || setStreamMethod == NULL)
... {
env->ExceptionDescribe();
env->ExceptionClear();
printf(" System 。 ");
return false ;
}
// System 。
env->CallStaticVoidMethod(systemClass, setStreamMethod, printStream);
if (env->ExceptionCheck() == JNI_TRUE)
... {
env->ExceptionDescribe();
env->ExceptionClear();
printf(" System 。 ");
return false ;
}
return true ;
}
2つ目は、Javaファイルをexeファイルにパッケージするのも簡単です.Dosプロンプトでcopyコマンドを実行します.C:\>copy test.exe+test.jar test.exe
実は、Javaパッケージファイルをexeファイルの末尾に追加します.「ファイルのプロパティ」ダイアログ・ボックスが開き、「圧縮ファイル」プロパティ・ページが表示されます.老舗のJBuilder.exe開発ツールが作成したexeファイルは、次のように生成されます.
後述:Eclipse 3.2とEclipse 3.3を使用すると、タスクマネージャで両者の違いが表示されます.Eclipse 3.2は、まずEclipse.exeファイルを起動し、次にEclipse.exeからJavaw.exeファイルを起動して仮想マシンを作成します.
Eclipse 3.2は、タスクマネージャでEclipse.exeとjavaw.exeの2つのプロセスとして表示されます.
Eclipse 3.3タスクマネージャにEclipse.exeのプロセスとして表示されます.
以上から分かるように、Eclipse 3.2とEclipse 3.3は異なる仮想マシンロード方式を採用している.
Eclipse 3.2はサブプロセスを作成する方法でjavaw.exeを呼び出して起動し、windowsの下でCreateProcess方法を使用することができます.この方法は簡単です.具体的にはEclipseソースコードを参照してください.
Eclipse 3.3 java仮想マシンをロードするもう1つの方法は、jvmの動的ライブラリをロードし、動的ライブラリのインタフェースを介してこのプロセス内でjava仮想マシンを起動することです.本稿の冒頭で採用した第2の方法.