微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在安装开始时卸载先前版本的产品会导致 Inno Setup 中的安装损坏

如何解决在安装开始时卸载先前版本的产品会导致 Inno Setup 中的安装损坏

我想使用 Inno Setup 删除旧的程序实例。 该程序不必安装在系统的特定部分才能运行,但我想制定一个标准并通过复制文件删除就在那里的旧实例。由于发生了一些更改,并且我想从注册表中删除以前安装的条目(32 位和 64 位安装是可能的,因此如果您想要两个安装程序,同一程序可能存在两个条目),我在假设中写了这个在 PreparetoInstall 部分运行卸载程序并删除文件后,安装将开始。

{ This is the part that is executed after you started the install }
function PreparetoInstall(var NeedsRestart: Boolean): String;
var
  ResultCode: integer;
  UninstallString: String;
  AppId: String;
begin
  AppId := '{#SetupSetting("AppId")}';
  AppId := copy(AppId,2,Length(AppId) - 1);
  if (IsWin64 And RegQueryStringValue(HKEY_LOCAL_MACHINE_64,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\'+AppId+'_is1','UninstallString',UninstallString)) then begin
    Exec(copy(UninstallString,Length(UninstallString) - 2),'/VERYSILENT','',SW_HIDE,ewWaitUntilTerminated,ResultCode)
    if RegKeyExists(HKEY_LOCAL_MACHINE_64,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\'+AppId+'_is1') then begin
      RegDeleteKeyIncludingSubkeys(HKEY_LOCAL_MACHINE_64,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\'+AppId+'_is1')
    end;
  end;
  if (RegQueryStringValue(HKEY_LOCAL_MACHINE_32,ResultCode)
    if RegKeyExists(HKEY_LOCAL_MACHINE_32,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\'+AppId+'_is1') then begin
      RegDeleteKeyIncludingSubkeys(HKEY_LOCAL_MACHINE_32,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\'+AppId+'_is1')
    end;
  end;

  If (DirIsSysLink(ExpandConstant('{app}')) = True) Then begin
    RenameFile(ExpandConstant('{app}'),ExpandConstant('{app}_link'));
    CreateDir(ExpandConstant('{app}'));
    Directorycopy(ExpandConstant('{app}_link'),ExpandConstant('{app}'));
    DelTree(ExpandConstant('{app}_link'),True,True);
  End;

  If (IsWin64) Then Begin
    If (DirExists('C:\Program Files (x86)\TargetProgram')) then begin 
      CleanupFolder('C:\Program Files (x86)\TargetProgram','X86') 
      If (DirIsSysLink('C:\Program Files (x86)\TargetProgram') = False) Then begin
        DelTree('C:\Program Files (x86)\TargetProgram',True)
      end
    end;
  End;
  
  If (DirExists('C:\Program Files\TargetProgram')) then begin
    CleanupFolder('C:\Program Files\TargetProgram','X64')
  end;
end;

{ Tries to remove existing installations and additional files in the folders that don't belong here before install starts }
function CleanupFolder(Folder: String; Num: String): Boolean;
var
  BolTmpVal: Boolean;
  FindRec: TFindRec;
  FileList: String;
begin
  BolcopyFailed := False;
  If (DirExists(Folder)) then begin
    FileList := '|a.file|b.dll|...|'
    if (FindFirst(Folder+'\*',FindRec)) then begin
      try
        repeat
          if (Pos('|'+LowerCase(FindRec.Name)+'|',FileList) <> 0) then begin//this is a file kNown to be installed later
            DeleteFile(Folder+'\'+FindRec.Name);
          end Else if ((Pos('unins0',FindRec.Name) = 1) And ((Pos('.exe',FindRec.Name) = 9) OR (Pos('.dat',FindRec.Name) = 9))) Then begin
            {Deleting the uninstall files seems to remove the actual installer itself...}
            //DeleteFile(Folder+'\'+FindRec.Name);
          End Else If ((FindRec.Name = '.') OR (FindRec.Name = '..')  OR (LowerCase(FindRec.Name) = 'backup')) Then Begin
            // do nothing with main directories or backup folder
          end Else begin
            //... some copy and paste backup of possible user-files not involved in the problem
          end;
        until not FindNext(FindRec);
      finally
        FindClose(FindRec);
      end;
    end;
  end;
end;

如果我用它来清除旧的安装,安装有时只包含 15 个应该安装的文件中的 8 个(在 [Files] 中定义,我可以看到它们被添加到编译器输出和通常安装)。所以我唯一的猜测为什么我得到的文件少于 15 个是应该在预安装过程中删除文件在安装过程中被删除。因此,如果我没有记错的话,所需的清理工作必须删除安装文件。但我找不到原因。

我认为安装本身在准备部分之后将内容放在目标文件夹中。那么我错了/如何修改代码以使安装有效?我知道我可以通过在安装程序结束前检查来测试这一点,但我想这不是一个神的练习......

我之前卸载的安装是这样的:

[Files]
Source: "Input\*"; DestDir: "{app}"; \
    Flags: ignoreversion recursesubdirs createallsubdirs 

[UninstallDelete]
Type: dirifempty; Name: "{app}" Type: dirifempty; Name: "C:\Program Files\A"

[Uninstallrun]
Filename: "{sys}\taskkill.exe"; Parameters: "/F /IM a.exe"; Flags:runhidden ; \
    StatusMsg: "Closing process"

解决方法

主卸载程序进程仅在临时文件夹中创建自己的副本,并运行子进程进行实际卸载。

因此,您代码中的 Exec,尽管有 ewWaitUntilTerminated,但实际上并不等待安装完成。因此可能会发生卸载程序和安装程序同时运行的情况。这自然会导致安装损坏。

您必须等待子卸载程序完成才能解决您的问题。快速而肮脏的解决方案是查找名称包含 _iu 的任何进程。见Inno Setup Pascal Script to search for running process

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。