如何卸载Program Files(x86)误装程序并重装至64位Program Files
自动卸载64位系统中Program Files(x86)里的旧版本InnoSetup程序
问题背景
我用InnoSetup制作的安装包默认将程序安装到Program Files(x86)目录,已错误分发该版本,大量64位Windows用户的软件都安装在这个x86目录中。
新版本安装包已调整为在64位系统下正确安装至Program Files目录,但旧版本并未自动卸载,仍留存于Program Files(x86),需要实现自动卸载旧版本的功能。
旧版本安装脚本(64位系统仍安装到Program Files(x86))
; Script generated by the Inno Setup Script Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! #define MyAppName "testApp" #define MyAppVersion "1.00" #define MyAppPublisher "taichi" #define MyAppURL "https://testApp.com/" #define MyAppExeName "testApp.exe" [Setup] ; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) AppId={{xxx-xxxx-xxxxx-xxx} AppName={#MyAppName} AppVersion={#MyAppVersion} ;AppVerName={#MyAppName} {#MyAppVersion} AppPublisher={#MyAppPublisher} AppPublisherURL={#MyAppURL} AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} DefaultDirName={autopf}\{#MyAppName} DisableProgramGroupPage=yes ; Uncomment the following line to run in non administrative install mode (install for current user only.) ;PrivilegesRequired=lowest OutputDir=C:\Users\taichi\Desktop OutputBaseFilename=testAppSetup Compression=lzma SolidCompression=yes WizardStyle=modern [Code] ///////////////////////////////////////////////////////////////////// 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; [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" [Tasks] Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked [Files] Source: "C:\Users\taichi\Documents\hold\testAppDevelop\dist\testApp\testApp.exe"; DestDir: "{app}"; Flags: ignoreversion [Icons] Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon [Run] Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: runasoriginaluser nowait postinstall skipifsilent
修改后的新版本脚本(可安装到Program Files,但旧版本未卸载)
; Script generated by the Inno Setup Script Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! #define MyAppName "testApp" #define MyAppVersion "1.00" #define MyAppPublisher "taichi" #define MyAppURL "https://testApp.com/" #define MyAppExeName "testApp.exe" [Setup] ; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) AppId={{xxx-xxxx-xxxxx-xxx} AppName={#MyAppName} AppVersion={#MyAppVersion} ;AppVerName={#MyAppName} {#MyAppVersion} AppPublisher={#MyAppPublisher} AppPublisherURL={#MyAppURL} AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} DefaultDirName={autopf}\{#MyAppName} DisableProgramGroupPage=yes ; Uncomment the following line to run in non administrative install mode (install for current user only.) ;PrivilegesRequired=lowest OutputDir=C:\Users\taichi\Desktop OutputBaseFilename=testAppSetup Compression=lzma SolidCompression=yes WizardStyle=modern ArchitecturesInstallIn64BitMode=x64 ArchitecturesAllowed=x64 [Code] ///////////////////////////////////////////////////////////////////// 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 GetUninstallString32: string; var sUnInstPath: string; sUnInstallString: String; begin Result := ''; sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{{A227028A-40D7-4695-8BA9-41DF6A3895C7}_is1'); { Your App GUID/ID } sUnInstallString := ''; if not RegQueryStringValue(HKLM32, sUnInstPath, 'UninstallString', sUnInstallString) then RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString); Result := sUnInstallString; end; ///////////////////////////////////////////////////////////////////// function IsUpgrade(): Boolean; begin Result := (GetUninstallString() <> ''); end; function IsUpgrade32(): Boolean; begin Result := (GetUninstallString32() <> ''); 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; function UnInstallOldVersion32(): 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; sUnInstallString := GetUninstallString32(); 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; begin UnInstallOldVersion32(); end; end; [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" [Tasks] Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked [Files] Source: "C:\Users\taichi\Documents\hold\testAppDevelop\dist\testApp\testApp.exe"; DestDir: "{app}"; Flags: ignoreversion [Icons] Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon [Run] Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: runasoriginaluser nowait postinstall skipifsilent
解决方案及修正后的脚本
你的新版本脚本存在两个关键问题:一是硬编码了32位卸载路径的GUID,二是卸载逻辑的执行时机和条件判断错误。以下是修正后的完整脚本:
; Script generated by the Inno Setup Script Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! #define MyAppName "testApp" #define MyAppVersion "1.00" #define MyAppPublisher "taichi" #define MyAppURL "https://testApp.com/" #define MyAppExeName "testApp.exe" [Setup] ; NOTE: 修正AppId格式,补上缺失的闭合大括号 AppId={{xxx-xxxx-xxxxx-xxx}} AppName={#MyAppName} AppVersion={#MyAppVersion} AppPublisher={#MyAppPublisher} AppPublisherURL={#MyAppURL} AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} DefaultDirName={autopf}\{#MyAppName} DisableProgramGroupPage=yes OutputDir=C:\Users\taichi\Desktop OutputBaseFilename=testAppSetup Compression=lzma SolidCompression=yes WizardStyle=modern ArchitecturesInstallIn64BitMode=x64 ArchitecturesAllowed=x64 [Code] ///////////////////////////////////////////////////////////////////// ; 获取64位程序的卸载字符串 function GetUninstallString64(): 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; ; 获取32位程序的卸载字符串(64位系统中对应Wow6432Node分支) function GetUninstallString32(): String; var sUnInstPath: String; sUnInstallString: String; begin sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1'); sUnInstallString := ''; ; 先检查HKLM32(全局安装的32位程序) if not RegQueryStringValue(HKLM32, sUnInstPath, 'UninstallString', sUnInstallString) then ; 再检查HKCU32(当前用户安装的32位程序) RegQueryStringValue(HKCU32, sUnInstPath, 'UninstallString', sUnInstallString); Result := sUnInstallString; end; ///////////////////////////////////////////////////////////////////// function Has64BitVersion(): Boolean; begin Result := (GetUninstallString64() <> ''); end; function Has32BitVersion(): Boolean; begin Result := (GetUninstallString32() <> ''); end; ///////////////////////////////////////////////////////////////////// ; 卸载64位旧版本 function UninstallOld64Version(): Integer; var sUnInstallString: String; iResultCode: Integer; begin Result := 0; sUnInstallString := GetUninstallString64(); 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; ; 卸载32位旧版本 function UninstallOld32Version(): Integer; var sUnInstallString: String; iResultCode: Integer; begin Result := 0; sUnInstallString := GetUninstallString32(); 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 = ssPrepare then begin ; 先卸载32位旧版本 if Has32BitVersion() then begin UninstallOld32Version(); end; ; 再卸载64位旧版本(如果存在) if Has64BitVersion() then begin UninstallOld64Version(); end; end; end; [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" [Tasks] Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked [Files] Source: "C:\Users\taichi\Documents\hold\testAppDevelop\dist\testApp\testApp.exe"; DestDir: "{app}"; Flags: ignoreversion [Icons] Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon [Run] Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: runasoriginaluser nowait postinstall skipifsilent
关键修改说明
- 修正AppId格式:原脚本中
AppId={{xxx-xxxx-xxxxx-xxx}缺少闭合大括号,导致注册表路径识别错误,修正为AppId={{xxx-xxxx-xxxxx-xxx}}。 - 动态获取32位卸载路径:不再硬编码GUID,而是用
{#emit SetupSetting("AppId")}动态获取当前脚本的AppId,保证和旧版本的卸载注册表项匹配。 - **
相关产品推荐
相关产品推荐

