欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
打造個(gè)性化Java啟動(dòng)器
http://blog.csdn.net/funcong/archive/2005/01/07/243362.aspx

作者:俞偉明 本文選自:賽迪網(wǎng) 主要內容:

________________________

一、Java程序的啟動(dòng)過(guò)程

 二、Windows平臺的啟動(dòng)器

 三、配置和使用

________________________

對 于普通用戶(hù)來(lái)說(shuō),Java最讓人不習慣的是程序的啟動(dòng)過(guò)程;即使對于富有經(jīng)驗的開(kāi)發(fā)者,為了用默認的裝載器啟動(dòng)Java程序,不得不編寫(xiě)大量批命令、腳本 文件,不得不在命令行環(huán)境下進(jìn)行大量的復制/粘貼操作,也很容易出現誤操作。

用慣了Windows方便快捷的GUI,人們早就習慣了通過(guò) 雙擊運行程序的方式。對于Java程序,要實(shí)現這個(gè)本機啟動(dòng)功能就必須編寫(xiě)定制的啟動(dòng)器。用定制啟動(dòng)器啟動(dòng)Java程序不僅方便了最終用戶(hù),而且使軟件作 品看起來(lái)更專(zhuān)業(yè)。本文就以Windows平臺為例,介紹如何構造Java定制啟動(dòng)器。



Java程序可以由任何本機運行的程序調用執行。所謂 Java啟動(dòng)器,就是一個(gè)專(zhuān)門(mén)用來(lái)啟動(dòng)Java程序的本機執行程序。最常見(jiàn)的啟動(dòng)器是Sun在Java Runtime Environment的/bin目錄中提供的啟動(dòng)器,就Windows平臺而言,它們是java.exe和javaw.exe。前者運行時(shí)打開(kāi)兩個(gè)窗 口:一個(gè)是接收System.out/err和啟動(dòng)器輸出的控制臺窗口,另一個(gè)是Java程序本身的窗口;javaw運行時(shí)不打開(kāi)控制臺窗口。在J2SE /EE平臺中,虛擬機以動(dòng)態(tài)庫的形式實(shí)現,也放在/bin目錄下。動(dòng)態(tài)庫的名字在Windows中是java.dll,在Unix中是java.so。所 謂“裝入虛擬機”,就是指裝入這個(gè)動(dòng)態(tài)庫。

提供給VM的參數可以通過(guò)兩種方式指定,或者是在啟動(dòng)器的命令行參數中指定,或者通過(guò)定義相應 的環(huán)境變量指定。只有一個(gè)參數例外——要啟動(dòng)的類(lèi)的名稱(chēng)只能在啟動(dòng)器的命令行參數中指定。雖然指定方式的多樣姓為人們各取所需帶來(lái)了方便,但不可否認地, 它也正是許多混亂的根源。使用定制啟動(dòng)器能夠完全避免這方面的問(wèn)題。

當VM結束啟動(dòng)類(lèi)的main()方法的運行,啟動(dòng)器調用 destroy()方法釋放各種資源并退出。應當注意的是,VM一旦開(kāi)始運行,我們就不能再卸載它。對于Java啟動(dòng)器來(lái)說(shuō),能否關(guān)閉VM無(wú)關(guān)緊要,因為 啟動(dòng)器會(huì )隨著(zhù)Java程序的退出而退出;然而,對于嵌入了VM的本機應用,例如瀏覽器,這意味著(zhù)有一塊內存被永久姓地占用,不能再收回。

二、 Windows平臺的啟動(dòng)器

搞清楚了Java程序的啟動(dòng)過(guò)程,我們就可以開(kāi)始編寫(xiě)啟動(dòng)器的代碼。下面這個(gè)啟動(dòng)器用C++寫(xiě)成,適合于所有 Windows平臺。



// Windows平臺下的Java程序啟動(dòng)器

// 適用于1.2或更高版本的VM

#include

#include

#include

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;

// 確定各種文件所在的路徑

// -應用的主目錄

char home[2000];

if (!GetApplicationHome(home, sizeof(home))) {

vShowError(" 不能確定應用的主目錄。");

return 0;

}

string sAppHome(home);

string sOption_AppHome = "-Dapplication.home=" + sAppHome;

string sJREPath = sAppHome + "\jre";

// -VM路徑

string sRuntimePath = sJREPath + "\bin\classic\";

string sJVMpath = sRuntimePath + "jvm.dll";

// -啟動(dòng)路徑

string sBootPath = sJREPath + "\lib";

string sOption_BootPath = "-Dsun.boot.class.path=" + sBootPath;

// -CLASSPATH

string sClassPath = sAppHome + "\classes";

string sOption_ClassPath = "-Djava.class.path=" + sClassPath;

// 設置VM參數

// vAddOption(string("-verbose"));

vAddOption(sOption_ClassPath);

vAddOption(sOption_AppHome);

// VM初始化參數

JavaVMInitArgs vm_args;

vm_args.version = 0x00010002;

vm_args.options = vm_options;

vm_args.nOptions = mctOptions;

vm_args.ignoreUnrecognized = JNI_TRUE;

// 裝入JVM庫

HINSTANCE hJVM = LoadLibrary(sJVMpath.c_str());

if( hJVM == NULL ){

vShowLastError("不能從下面的路徑裝入 JVM:" + sJVMpath);

return 0;

}

// 啟動(dòng)1.2/3/4 VM

CreateJavaVM lpfnCreateJavaVM = (CreateJavaVM) GetProcAddress(hJVM, "JNI_CreateJavaVM");

jintVMStartupReturnValue = (*lpfnCreateJavaVM) (&jvm, &env, &vm_args);

// 是否成功?

if (jintVMStartupReturnValue

FindClass(sStartupClass.c_str());

if (jclassStartup == NULL) {

string sErrorMessage ="找不到啟動(dòng)類(lèi)[" +sStartupClass + "]";

vShowError(sErrorMessage);

vDestroyVM(env, jvm);

return 0;

}

// 要啟動(dòng)的方法

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 = "找不到啟動(dòng)方法["+ sStartupClass + "."+ sStartupMethod_Identifier

+ "],類(lèi)型描述符是[" + sStartupMethod_TypeDescriptor + "]";

vShowError(sErrorMessage);

vDestroyVM(env, jvm);

return 0;

}

// 構造啟動(dòng)方法的參數

jstring jstringExampleArg;

jclass jclassString;

jobjectArray jobjectArray_args;

jstringExampleArg = env->NewStringUTF("string1");

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;

}

// 調用啟動(dòng)方法啟動(dòng)Java程序

env->CallStaticVoidMethod(jclassStartup, midStartup, jobjectArray_args);

// 在退出之前嘗試分離主線(xiàn)程

if (jvm->DetachCurrentThread() != 0) {

vShowError("分離主線(xiàn)程 失敗。\n");

}

// 只要還有非守護線(xiàn)程,下面的調用將一直被掛起

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(), "錯誤", MB_OK);

}

/* 在對話(huà)框中顯示錯誤信息,括號內包含

的 GetLastError錯誤信息 */

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();

}

/* 如果緩沖區是"c:\app\bin\java",則把"c:\app"放入 buf。*/

jboolean GetApplicationHome(char *buf, jint sz) {

char *cp;

GetModuleFileName(0, buf, sz);

*strrchr(buf, '\') = '{CONTENT}';

if ((cp = strrchr(buf, '\')) == 0) {

// 如果應用程序放在驅動(dòng)器的根目錄下,且不存在bin目錄

// 會(huì )出現這種情形

buf[0] = '{CONTENT}';

return JNI_FALSE;

}

return JNI_TRUE;

}



首 先,就象大多數Windows程序一樣,啟動(dòng)器需要一個(gè)WinMain()入口。與Windows這一特定平臺相關(guān)的問(wèn)題,除了必要的類(lèi)型轉換(例如對 CreateJavaVM()的轉換)之外,另外一個(gè)要注意的地方就是裝入VM的DLL文件。裝入DLL文件最可靠的辦法是顯式地調用 LoadLibrary()。裝入JVM之后,就可以利用內核調用GetProcAddress()獲得CreateJavaVM()的函數指針,然后調 用該指針啟動(dòng)VM。

在啟動(dòng)類(lèi)的標識符中使用的分隔符是斜杠,而不是句點(diǎn),即我們用“javabunny/JavaBunny”表示啟動(dòng) 類(lèi),而不是用“javabunny.JavaBunny”的形式。這是因為,FindClass()是一個(gè)虛擬機調用,而虛擬機內部用斜杠作為分隔符。隨 便說(shuō)明一下,這個(gè)例子把啟動(dòng)類(lèi)的名字(和其他一些配置選項)直接寫(xiě)進(jìn)了代碼之中(稱(chēng)為“硬編碼”),對于提供給最終用戶(hù)使用的產(chǎn)品,這種做法有其優(yōu)點(diǎn);但 對于開(kāi)發(fā)環(huán)境來(lái)說(shuō),這些值最好拿出來(lái)放在某個(gè)配置文件中。

Java程序啟動(dòng)后執行的第一個(gè)方法稱(chēng)為啟動(dòng)方法,通常是main()。本例通 過(guò)JNI調用GetStaticMethodID()獲得啟動(dòng)方法的ID。GetStaticMethodID()要求指定方法的名字(“main”)和 方法的類(lèi)型描述符(“([Ljava/lang/String;)V”)。這個(gè)類(lèi)型描述符表示方法的參數是一個(gè)字符串的數組,返回值類(lèi)型是void。有關(guān) 類(lèi)型描述符的更詳細的說(shuō)明,請參見(jiàn)JVM相關(guān)資料。注意,從這里可以看出,在使用定制啟動(dòng)器時(shí),Java程序的啟動(dòng)方法不必一定是static void的main方法,可以用任何方法作為Java程序中第一個(gè)執行的方法,甚至包括實(shí)例方法或構造函數。

示例程序中最后一個(gè)需要注意 的地方是jvm->DestroyJavaVM()調用。從表面看起來(lái),這個(gè)語(yǔ)句似乎是程序執行后進(jìn)行清理工作的方法,可有可無(wú)。其實(shí)不然,如果 Java程序是多線(xiàn)程的,在調用這個(gè)方法時(shí)程序仍舊在運行。例如,對于一個(gè)運行著(zhù)的Swing程序,如果它的main方法結 束,DestroyJavaVM()的執行將被阻塞,直至所有非守護線(xiàn)程都執行完畢,所以這行代碼是必不可少的。如果省略這行代碼,則當主線(xiàn)程執行完畢, 即使其他線(xiàn)程(例如Swing GUI的事件循環(huán))仍舊在運行,整個(gè)程序也會(huì )立即退出。

三、配置和使用

如前所述,這個(gè)啟 動(dòng)器以硬編碼的方式指定了啟動(dòng)類(lèi)的名字,但是沒(méi)有一個(gè)路徑是硬編碼的。這是定制啟動(dòng)器的優(yōu)點(diǎn)之一,由于所有的路徑都是相對的,用戶(hù)可以把整個(gè)Java應用 從一個(gè)文件夾拖到另一個(gè)驅動(dòng)器(或另一臺機器)的文件夾,程序的運行不會(huì )出現任何問(wèn)題。本文的啟動(dòng)器假定JRE總是在應用軟件所在目錄的一個(gè)子目錄下,也 就是說(shuō),JRE應當隨同應用軟件一起發(fā)布。這樣做的好處是使得應用軟件完全不依賴(lài)于用戶(hù)的環(huán)境,確保了JRE與應用程序的兼容姓。即使用戶(hù)系統中原來(lái)已經(jīng) 有JRE,增加一個(gè)額外的JRE也只不過(guò)稍微占用了一點(diǎn)磁盤(pán)空間,但卻能有效地保證應用軟件的穩定姓。

在某些場(chǎng)合,你可能需要將一些配置 參數移出程序,例如放入一個(gè)配置文件,特別是在需要頻繁改動(dòng)啟動(dòng)方式的開(kāi)發(fā)階段。建議移出程序之外的配置選項包括:?jiǎn)?dòng)類(lèi),類(lèi)的路徑,某些VM參數,例如 “-verbose”。


(#)

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
JNI介紹
如何在C/C++中調用Java
linux下通過(guò)JNI用C/C++中調用JAVA類(lèi)
Linux on POWER 的 JNI 編程實(shí)例
C/C++調用java,以及在cocos2d-x下的實(shí)現
使用JNI進(jìn)行混合編程:在C/C 中調用Java代碼
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久