自動安裝程式的實現演算法和原始碼 (轉)
自動的實現演算法和
李安東
關鍵字: 自解壓 自動安裝程式
假如我的程式要一個setup.exe程式,自動安裝一個,完成安裝後再把臨時全部刪除,應怎樣實現呢?雖然很簡單,但有一個問題需要解決,就是如何判斷何時已經安裝完成了呢?當然可以用
//Wait for until it tenated:
while(GetExitCodeProcess(newinfo.hProcess,&dwExitCode)&&
dwExitCode==STILL_ACTIVE);
來等待setup.exe執行結束,但是問題可能並不這麼簡單,常常是setup.exe又呼叫了別的子程式(例如_delis和inst5176什麼的),而setup.exe退出後,子程式並未退出,即任務仍未完成。因此這時刪除臨時檔案和資料夾仍然會導致安裝失敗和刪除檔案失敗。(我判斷早期的建立的TempMode自解壓檔案,在啟動setup.ex後安裝之所以會失敗,可能就是因為判斷錯誤,即在未完成安裝時就把臨時檔案刪除了。)
這個問題可以按如下方法解決(供參考):
1、用CreateEvent()建立一個事件hEvent;
2、啟動釋放在臨時目錄(比如C:TEMPMYTEMP)下的setup.exe後,然後如下語句:
//Wait for the self-extract process exit:
::ResetEvent(hEvent);
while(::WaitForSingle(hEvent,500)==WAIT_TIMEOUT)
{ IsExit(); }
即先將事件hEvent復位到無訊號狀態,並迴圈呼叫IsExit()函式;
3、在IsExit()函式中列舉系統中所有程式:
(1)、呼叫系統函式CreateToolhelp32Snapshot()並指定TH32CS_SNAPPROCESS引數,獲取一個系統中所有程式的列表(snapshot);
(2)、呼叫系統函式Process32First()獲取第一個程式的資訊;
(3)、迴圈呼叫系統函式Process32Next()獲取其餘程式的資訊。
上述函式呼叫中有一個引數lppe是一個PROCESSENTRY32型別的結構。lppe.th32ProcessID引數包含了獲取的程式識別符號;lppe.szExeFile為該程式的可執行檔案路徑和名稱。
因此在上述處理過程中,每次獲取lppe後均判斷lppe.szExeFile 中的路徑是否是安裝程式所在的臨時目錄,如果不存在這樣的程式,則說明安裝已經完成,則呼叫SetEvent()函式,將hEvent事件設定為有訊號,從而使第二步中的迴圈結束;
4、關閉事件控制程式碼,刪除安裝程式的所有臨時檔案和資料夾(例如MYTEMP),完成安裝。
注意:在呼叫列舉程式的函式時必須新增#include
下面是示例程式碼(已透過):
// Myx.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "re.h"
// Foward declarations of functions included in this code module:
BOOL InitInstance(HINSTANCE, int);
void RemoveThem(char *strPath);
void IsExit();
int ENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// Perfoapplication initialization:
return InitInstance (hInstance, nCmdShow);
}
//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
#if defined(_DE)
#define THISFILE_LENGTH 159785
#else
#define THISFILE_LENGTH 28672
#endif
char sPath[256];
HANDLE hEvent;
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
char sModule[256],sTemFile[256];
//Gets temporary directory:
::GetTempPath(255,sPath);
strcat(sPath,"Mytemp");
::CreateDirectory(sPath,NULL);
strcpy(sTemFile,sPath);
strcat(sTemFile,"");
::GetModuleFileName(NULL,sModule,255);
//Opens the module file:
HANDLE hFile=::CreateFile(sModule,GENERIC_READ,FILE_SHARE_READ,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(INVALID_HANDLE_VALUE==hFile)return 0;
//Creates the temprory file:
HANDLE hFileTemp=::CreateFile(sTemFile,GENERIC_WRITE|GENERIC_READ,
0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(INVALID_HANDLE_VALUE==hFileTemp)
{
::CloseHandle(hFile); return 0;
}
::SetFilePointer(hFile,THISFILE_LENGTH,NULL,FILE_BEGIN);
//Now begin to read and write:
while(TRUE)
{
BYTE buf[40*1024];
D dwNumberOfBytesRead;
if(::ReadFile(hFile,buf,40*1024,&dwNumberOfBytesRead,NULL)==0)
break;
DWORD dwNumberOfBytesWritten;
if(dwNumberOfBytesRead>0)
if(!::WriteFile(hFileTemp,buf,dwNumberOfBytesRead,
&dwNumberOfBytesWritten,NULL))break;
if(dwNumberOfBytesRead<40*1024)break;
}//while(TRUE)
::CloseHandle(hFile);
::CloseHandle(hFileTemp);
//Prepare to extract files and setup the application:
//Creates a auto-reset event object:
hEvent=::CreateEvent(
NULL, // SD
FALSE, // reset type
FALSE, // initial state
NULL // object name
);
//Executes self-extract file to extract files:
STARTUPINFO info;
PROCESS_INFORMATION newinfo;
::GetStartupInfo(&info);
::CreateProcess(sTemFile,NULL,NULL,NULL,FALSE,
CREATE_DEFAULT_ERROR_MODE,NULL,sPath,&info,&newinfo);
//Wait for the self-extract process exit:
::ResetEvent(hEvent);
while(::WaitForSingleObject(hEvent,500)==WAIT_TIMEOUT)
{
IsExit();
}
//Executes setup:
strcpy(sTemFile,sPath);
strcat(sTemFile,"");
::CreateProcess(sTemFile,NULL,NULL,NULL,FALSE,
CREATE_DEFAULT_ERROR_MODE|CREATE_NO_WINDOW,
NULL,sPath,&info,&newinfo);
//Wait for setup process and other started by it exit:
::ResetEvent(hEvent);
while(::WaitForSingleObject(hEvent,500)==WAIT_TIMEOUT)
{
IsExit();
}
::CloseHandle(hEvent);
//Remove tempary files and folders:
RemoveThem(sPath);
return FALSE;
}
void RemoveThem(char *strPath)
{
char strTemFile[256];
strcpy(strTemFile,strPath);
strcat(strTemFile,"*.*");
_FIND_DATA FindFileData;
HANDLE hFind=FindFirstFile(strTemFile,&FindFileData);
if(hFind!=INVALID_HANDLE_VALUE)
while(TRUE)
{
if(FindFileData.cFileName[0]=='.')
{
if(!FindNextFile(hFind,&FindFileData))break;
continue;
}
strcpy(strTemFile,strPath);
strcat(strTemFile,"");
strcat(strTemFile,FindFileData.cFileName);
if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
RemoveThem(strTemFile);//recursive call if it's a subdirectory.
else ::DeleteFile(strTemFile);//Delete it if it's a file.
if(!FindNextFile(hFind,&FindFileData))break;
}
::CloseHandle(hFind);
::RemoveDirectory(strPath);
}
void IsExit()
{
//Enumerate current processes:
//This process don't exit until the processes belonged to setup are all terminated:
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;
if(::Process32First(hSnapshot,&pe)==FALSE)
{
::CloseHandle(hSnapshot); goto L1;
}
if(_strnicmp(sPath,pe.szExeFile,len)==0)
blExist=TRUE;
while(blExist==FALSE && ::Process32Next(hSnapshot,&pe))
{
if(_strnicmp(sPath,pe.szExeFile,len)==0)
{
blExist=TRUE; break;
}
}
::CloseHandle(hSnapshot);
L1: if(blExist==FALSE) ::SetEvent(hEvent);
}
本文的意圖不是要開發一個工具軟體(因為市面上已有此類工具),其主要目的是想與有興趣的朋友一起切磋一下實現思路,說不定對某位朋友也許會有一點幫助(如需要完整程式碼可來信索取)。
*****************************************************************
附註:
1、感謝朋友們的鼓勵,因為要原始碼的朋友較多,現在請您直接到下面去原始碼:
/cnshare">
2、使用Sleep()函式確實更加簡便,謝謝高手指點。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992669/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- SpringBoot啟動程式碼和自動裝配原始碼分析Spring Boot原始碼
- mysql 的原始碼安裝方法及自動啟動方法MySql原始碼
- dephi 程式輸入法中英文自動切換實現的原始碼 (轉)原始碼
- 直播原始碼網站,實現文字自動翻轉效果原始碼網站
- PXE實現系統自動化安裝
- 安信實驗室教你如何實現Windows自動安裝!Windows
- 從原始碼安裝 Apache 1.3 和 PHP 4 (轉)原始碼ApachePHP
- Java學習之自動裝箱和自動拆箱原始碼分析Java原始碼
- 分析nuget原始碼,用nuget + nuget.server實現winform程式的自動更新原始碼ServerORM
- Mybatis自動程式碼生成器的實現MyBatis
- Kickstart+HTTP+DHCP+TFTP+PXElinux實現RedHat的網路自動安裝(轉)HTTPFTPLinuxRedhat
- 影片直播app原始碼,vue實現列表自動滾動的方式APP原始碼Vue
- 使用GitHub的Webhooks實現程式碼的自動部署GithubWebHook
- 透過 GitHub Actions 實現程式碼的自動編譯和釋出Github編譯
- 原始碼安裝Nginx和PHP原始碼NginxPHP
- Android程式碼實現APK檔案的安裝與解除安裝AndroidAPK
- 利用VC++程式設計實現程式自動啟動 (轉)C++程式設計
- 配置ks.cfg實現自動安裝過程
- Cobbler實現自動化安裝作業系統作業系統
- 自動升級系統的設計與實現(原始碼)原始碼
- 【轉】MySQL原始碼編譯安裝MySql原始碼編譯
- gitee 和 GitHub 的 webhook 的使用,實現伺服器程式碼的自動更新。GiteeGithubWebHook伺服器
- Android客戶端apk自動檢測更新自動下載自動安裝的實現方法Android客戶端APK
- mydumper自動化安裝指令碼指令碼
- DevOps:怎麼實現原始碼註釋和系統文件的自動化更新?dev原始碼
- Linux 安裝ffmpeg 實現音訊轉碼Linux音訊
- 一個二維碼實現蘋果和安卓的多個應用市場安裝包自動分發蘋果安卓
- Linux下原始碼安裝MySQL後設定開機自動啟動Linux原始碼MySql
- 利用 webhook 實現 Git 自動部署 Laravel 程式碼WebHookGitLaravel
- 手摸手,帶你實現程式碼自動部署
- jQuery實現的自動播放簡單程式碼例項jQuery
- MySQL的原始碼安裝及使用UDFs進行資料自動更新的教程MySql原始碼
- Gitee Webhook 實現自動拉取程式碼並編譯程式碼GiteeWebHook編譯
- 經典作業系統教材中的LRU演算法的自編c++實現及原始碼。 (轉)作業系統演算法C++原始碼
- golang一鍵自動安裝指令碼Golang指令碼
- LNMP一鍵自動安裝指令碼LNMP指令碼
- Redis 原始碼安裝以及啟動、停止Redis原始碼
- cent os 6.6 x64 自動原始碼安裝mysql 5.6指令碼原始碼MySql指令碼