自動安裝程式的實現演算法和原始碼 (轉)

worldblog發表於2007-12-13
自動安裝程式的實現演算法和原始碼 (轉)[@more@]

自動的實現演算法和

李安東


關鍵字: 自解壓 自動安裝程式

  假如我的程式要一個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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章