摘 要:本文介紹了自動安裝程序實現(xiàn)原理和方法。主要介紹了自解壓軟件包程序在完成解壓任務之后,如何自動完成安裝軟件的任務,包括如何等待子進程setup.exe、判斷setup.exe已經完成安裝,然后刪除臨時文件的方法和過程。
關鍵詞:自解壓;安裝程序
中圖分類號:TP311.52
假如有一個程序要調用一個setup.exe程序,自動安裝一個軟件,完成安裝后再把臨時文件和臨時目錄全部刪除,應怎樣實現(xiàn)呢?要實現(xiàn)自解壓包將包中的壓縮文件釋放完成后,自動啟動setup.exe安裝程序很簡單,但是完成安裝后要刪除先前釋放的臨時文件卻稍有麻煩。關鍵問題就是必須先判斷安裝程序已經完成了安裝,然后才能刪除。因為如果在還沒有完成安裝的時候刪除臨時文件和文件夾,可能會導致兩個嚴重后果:第一是安裝失敗,第二是某些文件無法刪除(這時它還在內存里)。
那么,如何判斷何時安裝程序已經完成了安裝任務呢?當然可以用while(GetExitCodeProcess(newinfo.hProcess,dwExitCode)dwExitCode==STILL_ACTIVE);來等待setup.exe運行結束。但是問題可能并不這么簡單,常常是setup.exe又調用了別的子進程(例如_delis和inst5176什么的),而setup.exe退出后,子進程并未退出,即安裝任務仍未完成。早期的WinRAR(2.50版)創(chuàng)建的TempMode自解壓文件,在自動啟動setup.exe后安裝過程之所以會失敗,我判斷可能就是因為判斷錯誤,即在未完成安裝時就把臨時文件刪除了。由此看來不應把setup.exe的退出作為安裝任務完成的標志,而應以是否存在臨時目錄下的任何程序仍處于執(zhí)行狀態(tài),作為判斷依據(jù)。即如果存在這樣的進程,則安裝仍未完成,反之則安裝已經完成。下面把筆者的實現(xiàn)思路介紹如下,供感興趣的同行參考。
1 解決步驟
以下把setup.exe叫做安裝程序,把我的程序叫做自動安裝程序。
現(xiàn)在假設自動安裝程序已經將臨時文件釋放到臨時文件夾,然后可以按照如下步驟來判斷何時安裝程序已經完成了安裝任務:
1.1 創(chuàng)建一個事件。即用系統(tǒng)函數(shù)CreateEvent()創(chuàng)建一個事件hEvent;
hEvent=::CreateEvent(
NULL, // SD
FALSE, // reset type
FALSE, // initial state
NULL // object name
);
以便于自動安裝程序等待安裝任務的完成。
1.2 啟動安裝程序。啟動釋放在臨時目錄(比如C:\WINDOWS\TEMP\MYTEMP)下的安裝程序setup.exe:
strcpy(sTemFile,sPath);strcat(sTemFile,\"\\Setup.exe\");
::CreateProcess(sTemFile,NULL,NULL,NULL,F(xiàn)ALSE,
CREATE_DEFAULT_ERROR_MODE|CREATE_NO_WINDOW,
NULL,sPath,info,newinfo);
其中sPath中的內容就是臨時目錄的路徑。
1.3 讓自動安裝程序循環(huán)等待。執(zhí)行如下語句讓自動安裝程序處于循環(huán)等待狀態(tài):
::ResetEvent(hEvent);
while(::WaitForSingleObject(hEvent,500)==WAIT_TIMEOUT)
{ IsExit();}
應當先將事件hEvent復位到無信號狀態(tài)。IsExit()函數(shù)的功能就是判斷當前是否有安裝程序進程及其子進程存在,若有則表明安裝過程仍在進行,若沒有則安裝已經完成。當安裝已經完成時函數(shù)IsExit()將事件hEvent置為有信號狀態(tài),從而結束循環(huán)等待。IsExit()函數(shù)的實現(xiàn)后面再單獨介紹。
1.4 關閉事件句柄、刪除臨時文件和文件夾。::CloseHandle(hEvent);RemoveThem(sPath);
其中sPath表示臨時目錄路徑,而函數(shù)RemoveThem()的作用是刪除以sPath為根的子目錄樹,限于篇幅這里將實現(xiàn)過程略去。
2 IsExit()函數(shù)的實現(xiàn)
主要是通過調用CreateToolhelp32Snapshot()、Process32First()和Process32Next()這三個系統(tǒng)函數(shù),通過列舉系統(tǒng)中進程,來判斷安裝過程是否完成。在調用列舉進程的函數(shù)時必須添加#include
2.1 調用系統(tǒng)函數(shù)CreateToolhelp32Snapshot()。在CreateToolhelp32Snapshot中()指定TH32CS_SNAPPROCESS參數(shù),獲取系統(tǒng)中所有進程的列表(snapshot):
HANDLE hSnapshot;PROCESSENTRY32 pe;
pe.dwSize=sizeof(pe);BOOL blExist=FALSE;
size_t len=strlen(sPath);
hSnapshot=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(hSnapshot<0) goto L1;
2.2 調用系統(tǒng)函數(shù)Process32First()。調用系統(tǒng)函數(shù)Process32First()獲取第一個進程的信息:
if(::Process32First(hSnapshot,pe)==FALSE)
{
::CloseHandle(hSnapshot); goto L1;
}
if(_strnicmp(sPath,pe.szExeFile,len)==0)
blExist=TRUE;
其中語句if(_strnicmp(sPath,pe.szExeFile,len)==0)就是判斷該進程的可執(zhí)行文件的路徑是否在安裝程序所在的臨時路徑下,若是則將blExist置為TRUE。參數(shù)pe是一個PROCESSENTRY32類型的結構,pe.th32ProcessID包含了獲取的進程標識符,pe.szExeFile為該進程的可執(zhí)行文件路徑和名稱。
2.3 循環(huán)調用系統(tǒng)函數(shù)Process32Next()。循環(huán)調用系統(tǒng)函數(shù)Process32Next()獲取其余進程的信息:
while(blExist==FALSE ::Process32Next(hSnapshot,pe))
{
if(_strnicmp(sPath,pe.szExeFile,len)==0)
{
blExist=TRUE; break;
}
}
作用與第2步中的基本相同。
2.4 設置事件。經過上述判斷,如果安裝過程已經結束,則將事件hEvent置為有信號狀態(tài):
::CloseHandle(hSnapshot);
L1:if(blExist==FALSE) ::SetEvent(hEvent);
3 結束語
本文簡要介紹了自動安裝程序實現(xiàn)原理和方法,其主要目的是想與有興趣的朋友一起切磋一下實現(xiàn)思路,希望能對軟件編程愛好的朋友有所幫助。所有實現(xiàn)代碼均已在VC++6.0和Windows XP下調試通過。
參考文獻:
[1]理查特.王建華等譯.Windows核心編程[M].北京:機械工業(yè)出版社,2006.
[2]唐麗麗.WINDOWS系統(tǒng)中代碼的動態(tài)嵌入執(zhí)行技術[J].武漢理工大學學報(交通科學與工程版),2002(01):51-55.
[3]本書編寫組.新編Windows API參考大全[M].北京:電子工業(yè)出版社,2000.
[4]王強,周明,李定國.Windows API for 2000/XP實例精解[M].北京:電子工業(yè)出版社,2002.
作者簡介:段英杰(1983-),女,江蘇常州人,講師,主要從事計算機軟件研究。
作者單位:常州劉國鈞高等職業(yè)技術學校,江蘇常州 213025