背景:
由于项目需求,需要在安装包安装之前,先卸载之前旧版本的安装。那么怎么能比较干净的卸载掉之前的旧版本安装包呢?
- 方法一:查找搜索安装路径并删除相应文件夹?删除快捷键?删除添加删除程序对应的项目,还有一些installsheild自己生成的文件,注册表键值等等?有没有遗漏?
- 方法二:还有没有别的方法,能够像添加删除程序中所作的,进行干净的卸载呢?
在开始前,这里先介绍Installshield的一个函数,具体大家可以参考Installshield的手册:
- 语法:LaunchAppAndWait (szProgram, szCmdLine, lWait);
- 说明:LaunchAppAndWait函数运行由szProgram指定的带有szCmdLine指定的命令行参数的应用程序。第三个参数,lWait指示安装在继续前是否要等待直到运行的应用程序终止。
一个安装程序只能监控由szProgram指定的应用程序;如果该应用程序要运行其它应用程序或进程,安装程序不能监控它们。因此,安装程序将在第一个应用程序结束后继续,即使那时由第一个应用程序运行的其它应用程序仍在运行。注意如果运行的应用程序终止失败,则安装程序将无限等待运行的应用程序完成。参数: szProgram 指定要被运行的应用程序的文件名。建议要指定应用程序的完整路径和文件名。如果你不包括一个路径,InstallShield将使用被Windows API 函数CreateProcess使用的相同的查找次序来定位文件。如果文件未能在这些位置找到,函数将失败。 如果应用程序的全限定名包括长文件夹名和/或一个长文件名,在把szCommand传递给LaunchAppAndWait之前先把它传递给LongPathToQuote。 szCmdLine 指定传递给运行的应用程序的命令行参数。为运行没有命令行参数的应用程序,传递一个空字符串。 lWait 指定安装程序在继续前是否要等待运行的应用程序终止。在该参数位置传递下列预定义常量之一: NOWAIT:指定安装程序在运行应用程序后立即继续,应用程序将和安装程序脚本同时运行。注意使用该参数等效于调用函数LaunchApp。 WAIT:指定安装程序必须等待直到由该函数运行的应用程序终止。
- LaunchAppAndWait(szPath,”/uninst”,LAAW_OPTION_WAIT_INCL_CHILD | LAAW_OPTION_WAIT);
- 其中,szPath的内容是通过函数RegDBGetKeyValueEx,获取待卸载的Product GUID对应于注册表中的”SOFTWARE//Microsoft//Windows//CurrentVersion//Uninstall//Product GUID”下,UninstallString的内容。其中,Product GUID的值需要查看Installsheild的Installation Information/Genaral Information中Product GUID的值。
- 卸载时,要求先卸载之前的旧安装包,卸载完后,才能继续新安装包的安装过程。一边卸载旧安装包,一边安装新安装包,容易引起错误,很多情况下也是不允许的。针对这点,需要注意的地方是,在调用LaunchAppAndWait方法等待老版本卸载完成的时候,一定要加上LAAW_OPTION_WAIT_INCL_CHILD ,主要是因为卸载的过程是Windows Install启动卸载程序,所以一定要等待Windows Install的子进程结束,否则两个同时运行,可能会导致错误。
这样还是会遇到问题,即:调用后,仍会弹出是否删除所有Feature,以及询问是否重启系统的对话框,这当然是肯定不能允许用户选择的。那么,如何解决上述问题?
- 首先用安装包安装好程序,通过在命令行运行安装包Setup.exe 给入参数/r,这时启动的依然是有界面操作的卸载操作,按照正常操作方式完成卸载。
- 完成上一步之后,会在系统的Windows或WINNT文件夹下产生一个Setup.iss文件,可以改名为Setup.iss.uninstall。
- 通过脚本,将此文件复制到Setup.exe同一目录下,这里要注意卸载脚本的调用时机,是在OnFirstUIBefore中进行,此时还没有实现文件的copy动作,可以通过把Setup.iss.uninstall首先添加到support中,然后通过函数XCopyFile,临时copy到setup.exe所在的路径下。
- 代码截选如下
RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
if (RegDBKeyExist("SOFTWARE//Microsoft//Windows//CurrentVersion//Uninstall//{D57D16E7-A863-4A65-A4AA-097E1632D154}") = 1)then
if(AskYesNo("Installing this version will replace previous one and do you want to continue?",YES )=0) then
exit;
else
uninstallDriverFunc();
szkey="SOFTWARE//Microsoft//Windows//CurrentVersion//Uninstall//{D57D16E7-A863-4A65-A4AA-097E1632D154}";
if (RegDBKeyExist(szkey) = 1)then // has the key
RegDBGetKeyValueEx(szkey,"UninstallString",nvType,szPath,nvSize);
VERCHEKER = SUPPORTDIR ^ "setup.iss";
XCopyFile ( VERCHEKER, "C://Program Files//InstallShield Installation Information//{D57D16E7-A863-4A65-A4AA-097E1632D154}", COMP_NORMAL );
szCMDLineTest = "/s /f1/"C://Program Files//InstallShield Installation Information//{D57D16E7-A863-4A65-A4AA-097E1632D154}//setup.iss/" ";
LaunchAppAndWait( szPath, szCMDLineTest, LAAW_OPTION_WAIT_INCL_CHILD | LAAW_OPTION_WAIT);
WaitForApplication(LAAW_PROCESS_INFORMATION.hProcess, LAAW_PROCESS_INFORMATION.dwProcessId, INFINITE, LAAW_OPTION_WAIT_INCL_CHILD | LAAW_OPTION_WAIT);
endif;
* 运行静默安装包:
- Setup.exe /s f1"Setup.iss.uninstall的路径" f2“指定生成静默安装Log的路径” 如果不通过f2指定log路径,则会在setup.exe同路径下生成一个Setup.log的文件。
这样就可以很干净的卸载之前不需要的安装包,并且整个卸载过程不需要用户干预,交互,需要注意的是RegDBGetKeyValueEx获取的UninstallString有时由于双引号等问题是需要字符串处理的。