Inno Setup:如何自动卸载以前安装的版本?
我正在使用Inno Setup来创build一个安装程序。
我希望安装程序自动卸载以前安装的版本,而不是覆盖它。 我怎样才能做到这一点?
您应该能够从registry中读取卸载string,给出AppId(即您在[Setup]
-section中用于AppID
的值)。 可以在Software\Microsoft\Windows\CurrentVersion\Uninstall\{AppId}\
(可以是HKLM
或HKCU
,所以最好检查两者) {AppId}
应该用您使用的实际值replace。 查找UninstallString
或QuietUninstallString
值,并使用Exec
函数从InitializeSetup()
事件函数中运行它。
更新:使用{uninstallexe}
的[Run]
条目删除了非工作替代解决scheme – 感谢所有指出这一点的评论者!
我用了以下。 我不知道这是最简单的方法,但它的工作原理。
这使用依赖于Inno Setup Preprocessor的{#emit SetupSetting("AppId")}
。 如果您不使用该function,请直接剪切并粘贴您的应用程序ID。
///////////////////////////////////////////////////////////////////// function GetUninstallString(): String; var sUnInstPath: String; sUnInstallString: String; begin sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1'); sUnInstallString := ''; if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString); Result := sUnInstallString; end; ///////////////////////////////////////////////////////////////////// function IsUpgrade(): Boolean; begin Result := (GetUninstallString() <> ''); end; ///////////////////////////////////////////////////////////////////// function UnInstallOldVersion(): Integer; var sUnInstallString: String; iResultCode: Integer; begin // Return Values: // 1 - uninstall string is empty // 2 - error executing the UnInstallString // 3 - successfully executed the UnInstallString // default return value Result := 0; // get the uninstall string of the old app sUnInstallString := GetUninstallString(); if sUnInstallString <> '' then begin sUnInstallString := RemoveQuotes(sUnInstallString); if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then Result := 3 else Result := 2; end else Result := 1; end; ///////////////////////////////////////////////////////////////////// procedure CurStepChanged(CurStep: TSetupStep); begin if (CurStep=ssInstall) then begin if (IsUpgrade()) then begin UnInstallOldVersion(); end; end; end;
备择scheme
另请参见本文的“Inno安装脚本示例进行版本比较”一节,并读取以前安装的版本号,并将该版本号与当前安装包的版本号进行比较。
使用Inno安装程序时,没有理由卸载以前的版本,除非该版本是由其他安装程序安装的。 否则,升级将自动处理。
如果你“只是想删除旧的图标”(因为你已经更改/更新),你可以使用这个:
; attempt to remove previous versions' icons [InstallDelete] Type: filesandordirs; Name: {group}\*;
这是“在安装开始”运行,所以基本上删除旧的图标,你的新的仍然会被安装在那里完成后。
我只是这样做的每一个安装“万一有什么改变”图标明智(无论如何这一切都得到重新安装)。
Craig McQueen提供的答案是完全可行的。 虽然,我会添加这些评论:
-
{#emit SetupSetting("AppId")}
代码不适用于我,所以我只是添加我的应用程序ID。 - 我不想执行我的卸载程序,因为我有一个INIconfiguration文件存储在卸载程序删除的AppData /文件夹中,我不希望它在安装新版本时被删除。 所以,我修改了一下Craig McQueen提供的代码,在取回path之后删除安装程序的目录。
所以,关于Craig McQueen的代码,变化是:
- 检索
InstallLocation
键而不是UninstallString
键。 - 使用
DelTree
函数而不是Exec(sUnInstallString, ...)
我被编辑@Crain Mc-Queen代码,我认为这个代码更好,因为不需要在不同的项目中修改:
[Code] function GetNumber(var temp: String): Integer; var part: String; pos1: Integer; begin if Length(temp) = 0 then begin Result := -1; Exit; end; pos1 := Pos('.', temp); if (pos1 = 0) then begin Result := StrToInt(temp); temp := ''; end else begin part := Copy(temp, 1, pos1 - 1); temp := Copy(temp, pos1 + 1, Length(temp)); Result := StrToInt(part); end; end; function CompareInner(var temp1, temp2: String): Integer; var num1, num2: Integer; begin num1 := GetNumber(temp1); num2 := GetNumber(temp2); if (num1 = -1) or (num2 = -1) then begin Result := 0; Exit; end; if (num1 > num2) then begin Result := 1; end else if (num1 < num2) then begin Result := -1; end else begin Result := CompareInner(temp1, temp2); end; end; function CompareVersion(str1, str2: String): Integer; var temp1, temp2: String; begin temp1 := str1; temp2 := str2; Result := CompareInner(temp1, temp2); end; function InitializeSetup(): Boolean; var oldVersion: String; uninstaller: String; ErrorCode: Integer; vCurID :String; vCurAppName :String; begin vCurID:= '{#SetupSetting("AppId")}'; vCurAppName:= '{#SetupSetting("AppName")}'; //remove first "{" of ID vCurID:= Copy(vCurID, 2, Length(vCurID) - 1); // if RegKeyExists(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + vCurID + '_is1') then begin RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + vCurID + '_is1', 'DisplayVersion', oldVersion); if (CompareVersion(oldVersion, '{#SetupSetting("AppVersion")}') < 0) then begin if MsgBox('Version ' + oldVersion + ' of ' + vCurAppName + ' is already installed. Continue to use this old version?', mbConfirmation, MB_YESNO) = IDYES then begin Result := False; end else begin RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + vCurID + '_is1', 'UninstallString', uninstaller); ShellExec('runas', uninstaller, '/SILENT', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode); Result := True; end; end else begin MsgBox('Version ' + oldVersion + ' of ' + vCurAppName + ' is already installed. This installer will exit.', mbInformation, MB_OK); Result := False; end; end else begin Result := True; end; end;
您可以在[code]部分中执行卸载程序。 你必须弄清楚如何获得现有的卸载程序的path。 为了简单起见,当我安装我的应用程序时,我添加一个registrystring值,指向包含卸载程序的文件夹,只需在InitializeWizardcallback中执行卸载程序。
请记住,Inno安装程序卸载程序名称的forms都是uninsnnn.exe,您需要在代码中考虑这一点。
对于任何使用上面提到的GetUninstallString()
强制在CurStepChanged()
内部卸载并且存在磁盘caching问题的人,请参阅下面的相关解决scheme,在卸载unistaller之后实际等待一段时间才能删除卸载程序exe!
磁盘caching与inno-setup的问题?
我一定会错过一些东西。 在删除旧安装之前, 新文件将被复制到目标目录。 然后卸载程序删除它们并删除目录。
不要使用[Run]部分,而要使用[UninstallRun]。 事实上,[Run]下的程序在安装后执行,导致在安装后立即卸载程序: – | 而是在安装之前评估[UninstallRun]部分。
请点击此链接: http : //news.jrsoftware.org/news/innosetup/msg55323.html
在InitializeSetup()函数中,用户提示卸载旧的旧版本后,可以调用“MSIEXEC / x {您的程序ID}