时间:2022-09-24 12:25:21
摘 要:本文介绍了自动安装程序实现原理和方法。主要介绍了自解压软件包程序在完成解压任务之后,如何自动完成安装软件的任务,包括如何等待子进程setup.exe、判断setup.exe已经完成安装,然后删除临时文件的方法和过程。
关键词:自解压;安装程序
中图分类号:TP311.52
假如有一个程序要调用一个setup.exe程序,自动安装一个软件,完成安装后再把临时文件和临时目录全部删除,应怎样实现呢?要实现自解压包将包中的压缩文件释放完成后,自动启动setup.exe安装程序很简单,但是完成安装后要删除先前释放的临时文件却稍有麻烦。关键问题就是必须先判断安装程序已经完成了安装,然后才能删除。因为如果在还没有完成安装的时候删除临时文件和文件夹,可能会导致两个严重后果:第一是安装失败,第二是某些文件无法删除(这时它还在内存里)。
那么,如何判断何时安装程序已经完成了安装任务呢?当然可以用while(GetExitCodeProcess(newinfo.hProcess,&dwExitCode)&&dwExitCode==STILL_ACTIVE);来等待setup.exe运行结束。但是问题可能并不这么简单,常常是setup.exe又调用了别的子进程(例如_delis和inst5176什么的),而setup.exe退出后,子进程并未退出,即安装任务仍未完成。早期的WinRAR(2.50版)创建的TempMode自解压文件,在自动启动setup.exe后安装过程之所以会失败,我判断可能就是因为判断错误,即在未完成安装时就把临时文件删除了。由此看来不应把setup.exe的退出作为安装任务完成的标志,而应以是否存在临时目录下的任何程序仍处于执行状态,作为判断依据。即如果存在这样的进程,则安装仍未完成,反之则安装已经完成。下面把笔者的实现思路介绍如下,供感兴趣的同行参考。
1 解决步骤
以下把setup.exe叫做安装程序,把我的程序叫做自动安装程序。
现在假设自动安装程序已经将临时文件释放到临时文件夹,然后可以按照如下步骤来判断何时安装程序已经完成了安装任务:
1.1 创建一个事件。即用系统函数CreateEvent()创建一个事件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,FALSE,
CREATE_DEFAULT_ERROR_MODE|CREATE_NO_WINDOW,
NULL,sPath,&info,&newinfo);
其中sPath中的内容就是临时目录的路径。
1.3 让自动安装程序循环等待。执行如下语句让自动安装程序处于循环等待状态:
::ResetEvent(hEvent);
while(::WaitForSingleObject(hEvent,500)==WAIT_TIMEOUT)
{ IsExit(); }
应当先将事件hEvent复位到无信号状态。IsExit()函数的功能就是判断当前是否有安装程序进程及其子进程存在,若有则表明安装过程仍在进行,若没有则安装已经完成。当安装已经完成时函数IsExit()将事件hEvent置为有信号状态,从而结束循环等待。IsExit()函数的实现后面再单独介绍。
1.4 关闭事件句柄、删除临时文件和文件夹。::CloseHandle(hEvent); RemoveThem(sPath);
其中sPath表示临时目录路径,而函数 RemoveThem()的作用是删除以sPath为根的子目录树,限于篇幅这里将实现过程略去。
2 IsExit()函数的实现
主要是通过调用CreateToolhelp32Snapshot()、Process32First()和Process32Next()这三个系统函数,通过列举系统中进程,来判断安装过程是否完成。在调用列举进程的函数时必须添加#include指令。实现步骤如下:
2.1 调用系统函数CreateToolhelp32Snapshot()。在CreateToolhelp32Snapshot中()指定TH32CS_SNAPPROCESS参数,获取系统中所有进程的列表(snapshot):
HANDLE hSnapshot;PROCESSENTRY32 pe;
pe.dwSize=sizeof(pe);BOOL blExist=FALSE;
size_t len=strlen(sPath);
hSnapshot=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(hSnapshot
2.2 调用系统函数Process32First()。调用系统函数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)就是判断该进程的可执行文件的路径是否在安装程序所在的临时路径下,若是则将 blExist置为TRUE。参数pe是一个PROCESSENTRY32类型的结构,pe.th32ProcessID包含了获取的进程标识符,pe.szExeFile为该进程的可执行文件路径和名称。
2.3 循环调用系统函数Process32Next()。循环调用系统函数Process32Next()获取其余进程的信息:
while(blExist==FALSE && ::Process32Next(hSnapshot,&pe))
{
if(_strnicmp(sPath,pe.szExeFile,len)==0)
{
blExist=TRUE; break;
}
}
作用与第2步中的基本相同。
2.4 设置事件。经过上述判断,如果安装过程已经结束,则将事件hEvent置为有信号状态:
::CloseHandle(hSnapshot);
L1: if(blExist==FALSE) ::SetEvent(hEvent);
3 结束语
本文简要介绍了自动安装程序实现原理和方法,其主要目的是想与有兴趣的朋友一起切磋一下实现思路,希望能对软件编程爱好的朋友有所帮助。所有实现代码均已在VC++6.0和Windows XP下调试通过。
参考文献:
[1]理查特.王建华等译.Windows核心编程[M].北京:机械工业出版社,2006.
[2]唐丽丽.WINDOWS系统中代码的动态嵌入执行技术[J].武汉理工大学学报(交通科学与工程版),2002(01):51-55.
[3]本书编写组.新编Windows API参考大全[M].北京:电子工业出版社,2000.
[4]王强,周明,李定国.Windows API for 2000/XP实例精解[M].北京:电子工业出版社,2002.
作者简介:段英杰(1983-),女,江苏常州人,讲师,主要从事计算机软件研究。
作者单位:常州刘国钧高等职业技术学校,江苏常州 213025