分享
 
 
 

自动安装程序的实现算法和源代码

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

自动安装程序的实现算法和源代码

李安东

关键字: 自解压 自动安装程序

假如我的程序要调用一个setup.exe程序,自动安装一个软件,完成安装后再把临时文件全部删除,应怎样实现呢?虽然很简单,但有一个问题需要解决,就是如何判断何时已经安装完成了呢?当然可以用

//Wait for until it terminated:

while(GetExitCodeProcess(newinfo.hProcess,&dwExitCode)&&

dwExitCode==STILL_ACTIVE);

来等待setup.exe运行结束,但是问题可能并不这么简单,常常是setup.exe又调用了别的子进程(例如_delis和inst5176什么的),而setup.exe退出后,子进程并未退出,即任务仍未完成。因此这时删除临时文件和文件夹仍然会导致安装失败和删除文件失败。(我判断早期的WinRAR创建的TempMode自解压文件,在启动setup.ex后安装之所以会失败,可能就是因为判断错误,即在未完成安装时就把临时文件删除了。)

这个问题可以按如下方法解决(供参考):

1、用系统函数CreateEvent()创建一个事件hEvent;

2、启动释放在临时目录(比如C:\WINDOWS\TEMP\MYTEMP)下的setup.exe后,然后执行如下语句:

//Wait for the self-extract process exit:

::ResetEvent(hEvent);

while(::WaitForSingleObject(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 <Tlhelp32.h>指令。

下面是示例代码(已调试通过):

// MySfx.cpp : Defines the entry point for the application.

//

#include "stdafx.h"

#include "resource.h"

// Foward declarations of functions included in this code module:

BOOL InitInstance(HINSTANCE, int);

void RemoveThem(char *strPath);

void IsExit();

int APIENTRY WinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nCmdShow)

{

// Perform application 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(_DEBUG)

#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,"\Sfx.exe");

::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];

DWORD 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,"\Setup.exe");

::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,"\\*.*");

WIN32_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、感谢朋友们的鼓励,因为要源码的朋友较多,现在请您直接到下面去下载源代码:

http://www.csdn.net/cnshare

2、使用Sleep()函数确实更加简便,谢谢高手指点。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有