最近有網友問:如何讓一個JAR檔案隨JVM啟動時運行?java.exe是不能夠做成這樣的,不過可以自己定製java.exe,定製java.exe在如下情況有用:
1.不想程式的進程名顯示為java.exe
2.希望程式雙擊就可以運行。
下面是一段範例程式碼:
// JVM_CPP.cpp : Defines the entry point for the console application.<br />//<br />#include "stdafx.h"<br />#include "windows.h"<br />#include <jni.h><br />typedef jint (JNICALL *JNICREATEPROC)(JavaVM**, void**, void*);<br />bool setStream(JNIEnv* env, const char* pszFileName, const char* pszMethod);<br />//啟動java虛擬機器方法<br />bool startJvm()<br />{<br /> //jvm動態庫的路徑<br /> const TCHAR szJvmPath[] = _T("E://java//jdk//jdk1.6.0//jre//bin//server//jvm.dll");<br /> //java 虛擬機器的啟動參數,每個參數寫一項,不能合在一起寫<br /> int nOptionCount = 2;<br /> JavaVMOption options[2];<br /> options[1].optionString = "-Xmx256M";<br /> //設定classpath<br /> options[0].optionString = "-Djava.class.path=./Test.jar;";<br /> JavaVMInitArgs vm_args;<br /> vm_args.version = JNI_VERSION_1_4;<br /> vm_args.options = options;<br /> vm_args.nOptions = nOptionCount;<br /> vm_args.ignoreUnrecognized = JNI_TRUE;<br /> //啟動類,注意分割符是/,例如啟動類test.JTest應該寫成 test/JTest<br /> const char szStartClass[] = "com/kortide/JVM/Test";<br /> //啟動方法,通常是main函數,你也可以設定成其他函數<br /> const char szStartMethod[] = "main";<br /> //重導向檔案<br /> const char* szStdoutFileName = "stdout.txt";<br /> const char* szStderrFileName = "stderr.txt";<br /> //java程式的命令列參數<br /> int nParamCount = 2;<br /> const char* szParams[2] =<br /> {<br /> "arg1", "arg2"<br /> };<br /> //載入JVM。<br /> HINSTANCE jvmDll = LoadLibrary(szJvmPath);<br /> if (jvmDll == NULL)<br /> {<br /> printf("載入JVM動態庫錯誤。%l", ::GetLastError());<br /> return false;<br /> }<br /> //尋找JNI_CreateJavaVM過程。<br /> JNICREATEPROC jvmCreateProc = (JNICREATEPROC) GetProcAddress(jvmDll,<br /> "JNI_CreateJavaVM");<br /> if (jvmCreateProc == NULL)<br /> {<br /> FreeLibrary(jvmDll);<br /> printf("尋找JNI_CreateJavaVM過程錯誤。%l", ::GetLastError());<br /> return false;<br /> }<br /> //建立JVM。<br /> JNIEnv* env;<br /> JavaVM* jvm;<br /> jint r = (jvmCreateProc) (&jvm, (void**) &env, & vm_args);<br /> if (r < 0 || jvm == NULL || env == NULL)<br /> {<br /> FreeLibrary(jvmDll);<br /> printf("建立JVM發生錯誤。");<br /> return false;<br /> }<br /> //重導向stdout, stderr到輸出檔案<br /> if (!setStream(env, szStdoutFileName, "setOut"))<br /> {<br /> printf("設定stdout輸出檔案失敗");<br /> return false;<br /> }<br /> if (!setStream(env, szStderrFileName, "setErr"))<br /> {<br /> printf("設定stderr輸出檔案失敗");<br /> return false;<br /> }<br /> //載入啟動類。<br /> jclass serviceClass = env->FindClass(szStartClass);<br /> if (env->ExceptionCheck() == JNI_TRUE || serviceClass == NULL)<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> FreeLibrary(jvmDll);<br /> printf("載入啟動類失敗。");<br /> return false;<br /> }<br /> //啟動方法<br /> jmethodID mid = env->GetStaticMethodID(serviceClass, szStartMethod,<br /> "([Ljava/lang/String;)V");<br /> if (env->ExceptionCheck() == JNI_TRUE || mid == NULL)<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> FreeLibrary(jvmDll);<br /> printf("尋找啟動方法失敗。");<br /> return false;<br /> }<br /> //尋找String類。<br /> jclass stringClass = env->FindClass("java/lang/String");<br /> if (env->ExceptionCheck() == JNI_TRUE || stringClass == NULL)<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> FreeLibrary(jvmDll);<br /> printf("尋找String類失敗。");<br /> return false;<br /> }<br /> jstring jstr;<br /> jobjectArray args = 0;<br /> args = env->NewObjectArray(2, stringClass, 0);<br /> for (int i = 0; i < nParamCount; i++)<br /> {<br /> jstr = env->NewStringUTF(szParams[i]);<br /> if (jstr == 0)<br /> {<br /> printf("分配String失敗/n");<br /> if (env->ExceptionOccurred())<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> }<br /> return false;<br /> }<br /> env->SetObjectArrayElement(args, i, jstr);<br /> if (env->ExceptionCheck() == JNI_TRUE)<br /> {<br /> printf("設定參數失敗/n");<br /> if (env->ExceptionOccurred())<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> }<br /> return false;<br /> }<br /> }<br /> //調用啟動類的啟動方法啟動Java程式<br /> //env->CallStaticVoidMethod(serviceClass, mid, parameterArray);<br /> env->CallStaticVoidMethod(serviceClass, mid, args);<br /> if (env->ExceptionCheck() == JNI_TRUE)<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> FreeLibrary(jvmDll);<br /> return false;<br /> }<br /> return true;<br />}<br />//設定輸出資料流的方法<br />bool setStream(JNIEnv* env, const char* pszFileName, const char* pszMethod)<br />{<br /> int pBufferSize = 1024;<br /> char* pBuffer = new char[pBufferSize];<br /> //建立字串對象。<br /> jstring pathString = env->NewStringUTF(pszFileName);<br /> if (env->ExceptionCheck() == JNI_TRUE || pathString == NULL)<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> printf("建立字串失敗。");<br /> return false;<br /> }<br /> //尋找FileOutputStream類。<br /> jclass fileOutputStreamClass = env->FindClass("java/io/FileOutputStream");<br /> if (env->ExceptionCheck() == JNI_TRUE || fileOutputStreamClass == NULL)<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> printf("尋找FileOutputStream類失敗。");<br /> return false;<br /> }<br /> //尋找FileOutputStream類構造方法。<br /> jmethodID fileOutputStreamConstructor = env->GetMethodID(fileOutputStreamClass,<br /> "<init>",<br /> "(Ljava/lang/String;)V");<br /> if (env->ExceptionCheck() == JNI_TRUE || fileOutputStreamConstructor == NULL)<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> printf("尋找FileOutputStream類構造方法失敗。");<br /> return false;<br /> }<br /> //建立FileOutputStream類的對象。<br /> jobject fileOutputStream = env->NewObject(fileOutputStreamClass,<br /> fileOutputStreamConstructor, pathString);<br /> if (env->ExceptionCheck() == JNI_TRUE || fileOutputStream == NULL)<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> printf("建立FileOutputStream類的對象失敗。");<br /> return false;<br /> }<br /> //尋找PrintStream類。<br /> jclass printStreamClass = env->FindClass("java/io/PrintStream");<br /> if (env->ExceptionCheck() == JNI_TRUE || printStreamClass == NULL)<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> printf("尋找PrintStream類失敗。");<br /> return false;<br /> }<br /> //尋找PrintStream類構造方法。<br /> jmethodID printStreamConstructor = env->GetMethodID(printStreamClass,<br /> "<init>",<br /> "(Ljava/io/OutputStream;)V");<br /> if (env->ExceptionCheck() == JNI_TRUE || printStreamConstructor == NULL)<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> printf("尋找PrintStream類構造方法失敗。");<br /> return false;<br /> }<br /> //建立PrintStream類的對象。<br /> jobject printStream = env->NewObject(printStreamClass,<br /> printStreamConstructor, fileOutputStream);<br /> if (env->ExceptionCheck() == JNI_TRUE || printStream == NULL)<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> printf("建立PrintStream類的對象失敗。");<br /> return false;<br /> }<br /> //尋找System類。<br /> jclass systemClass = env->FindClass("java/lang/System");<br /> if (env->ExceptionCheck() == JNI_TRUE || systemClass == NULL)<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> printf("尋找System類失敗。");<br /> return false;<br /> }<br /> //尋找System類設定方法。<br /> jmethodID setStreamMethod = env->GetStaticMethodID(systemClass, pszMethod,<br /> "(Ljava/io/PrintStream;)V");<br /> if (env->ExceptionCheck() == JNI_TRUE || setStreamMethod == NULL)<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> printf("尋找System類設定方法失敗。");<br /> return false;<br /> }<br /> //設定System類的流。<br /> env->CallStaticVoidMethod(systemClass, setStreamMethod, printStream);<br /> if (env->ExceptionCheck() == JNI_TRUE)<br /> {<br /> env->ExceptionDescribe();<br /> env->ExceptionClear();<br /> printf("設定System類的流失敗。");<br /> return false;<br /> }<br /> return true;<br />}<br />int _tmain(int argc, _TCHAR* argv[])<br />{<br /> startJvm();<br /> return 0;<br />}<br />
上面的代碼參考了《如何用C++自行載入Java虛擬機器》http://www.wangchao.net.cn/bbsdetail_147855.html