首页 > 解决方案 > Inno Setup:[Run] 部分中的错误处理

问题描述

我一直在使用 Inno Setup 创建我的第一个安装程序,当它们工作时,我想研究一些更深刻的错误处理,以防在安装过程中出现问题。

这是包含我到目前为止的脚本片段。所有这些都有效,问题如下。

[Components]
Name: "base"; Description: "Install base files needed for this application"; Types: full compact custom; Flags: fixed
Name: "fonts"; Description: "Install Spartan fonts for a correct rendering of the application"; Types: full custom
Name: "updater"; Description: "Create a scheduled task to run the component updater on a daily basis"; Types: full custom

[Tasks]
Name: "update"; Description: "Run the updater after the installation to bring all application files up to date"

[Files]
; Application files
Source: "{#MyAppSourceNetwork1}\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Components: base
Source: "{#MyAppSourceNetwork1}\{#MyAppcfgName}"; DestDir: "{app}"; Flags: ignoreversion; Components: base
Source: "{#MyAppSourceNetwork1}\Source\Componenten_COM\*"; DestDir: "{app}\Componenten_COM"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: base
Source: "{#MyAppSourceNetwork1}\Source\Componenten_RegAsm\*"; DestDir: "{app}\Componenten_RegAsm"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: base
Source: "{#MyAppSourceNetwork2}\*"; DestDir: "{#MyAppLocalFolderLib}\OCXinstaller"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: base

; Updater
Source: "{#MyAppSource}\Updater\*"; DestDir: "{#MyAppLocalFolderLib}\Updater"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: base

[Run]
; Create scheduled task for updater
Filename: "powershell"; \
  Parameters: "-Executionpolicy Bypass -NoProfile -WindowStyle Hidden -Command ""Register-ScheduledTask -TaskName '{#MyAppTSUpdaterName}' -Description 'Smartclient component updater' -User System -Action (New-ScheduledTaskAction -Execute wscript -Argument '{#MyAppLocalFolderLib}\Updater\{#MyAppUpdateScript}') -Trigger (New-ScheduledTaskTrigger -Daily -At 07:00) -Settings (New-ScheduledTaskSettingsSet -StartWhenAvailable -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -DontStopOnIdleEnd -ExecutionTimeLimit (New-TimeSpan -Hours 2) -MultipleInstances IgnoreNew)"""; \
  Description: "Create scheduled task for updater"; \
  StatusMsg: "Creating scheduled task ""{#MyAppTSUpdaterName}""..."; \
  Flags: runhidden; \
  Components: updater

; Run scheduled task for updater
Filename: "wscript"; \
  Parameters: """{#MyAppLocalFolderLib}\Updater\{#MyAppUpdateScript}"""; \
  Description: "Run Smartclient component updater"; \
  StatusMsg: "Running Smartclient updater. Please wait, this will take a few minutes..."; \
  Flags: runhidden; \
  BeforeInstall: SetMarqueeProgress(True); \
  AfterInstall: SetMarqueeProgress(False); \
  Tasks: update

; Offer option to launch application after installation
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent unchecked

[Code]
// Show infinite progress bar while waiting
procedure SetMarqueeProgress(Marquee: Boolean);
begin
  if Marquee then
  begin
    WizardForm.ProgressGauge.Style := npbstMarquee;
  end
    else
  begin
    WizardForm.ProgressGauge.Style := npbstNormal;
  end;
end;

出于测试的目的,我特意在命令中写了一些错误(RRR egister -ScheduledTask / UUU pdater / NNN otepad),在下面的日志文件中,您可以清楚地看到命令没有返回代码 0。

在安装过程中,我收到了 wscript 和 notepad 命令的消息框,清楚地表明出了问题,带有返回码和一个 OK 按钮。但是,Powershell命令根本没有给出消息。它仅在我写错命令(PPPowershell.exe)时返回错误,但在参数标志中有错误时不返回。知道为什么吗?因为我确信 Powershell 返回一些漂亮的红线,表明发生了错误。

此外,我注意到 Inno Setup 在日志中写道安装成功(我的代码段中的第 7 行),尽管它甚至仍然需要从 [Run] 部分开始。当我编写没有拼写错误的命令时,安装程​​序会正确执行所有操作,但即使某些操作未成功,我也无法对安装程序如何指示成功表示信心。如果安装,为什么不将 [Run] 块视为不可或缺的一部分?

2020-06-10 08:52:15.025   Saving uninstall information.
2020-06-10 08:52:15.025   Deleting uninstall key left over from previous administrative 32-bit install.
2020-06-10 08:52:15.027   Creating new uninstall key: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\{C3DAA6E8-7152-40C7-8487-F4A1BDC3EB92}_is1
2020-06-10 08:52:15.027   Writing uninstall key values.
2020-06-10 08:52:15.030   Detected previous non administrative install? No
2020-06-10 08:52:15.030   Detected previous administrative 64-bit install? No
2020-06-10 08:52:15.047   Installation process succeeded.
2020-06-10 08:52:15.052   -- Run entry --
2020-06-10 08:52:15.052   Run as: Current user
2020-06-10 08:52:15.053   Type: Exec
2020-06-10 08:52:15.053   Filename: powershell
2020-06-10 08:52:15.053   Parameters: -Executionpolicy Bypass -NoProfile -WindowStyle Hidden -Command "RRRegister-ScheduledTask -TaskName 'Smartclient Updater' -Description 'Smartclient component updater' -User System -Action (New-ScheduledTaskAction -Execute wscript -Argument 'C:\Smartclient_MH_LIB\Updater\Mediahuis_Smartclient_Components_Updater.vbs') -Trigger (New-ScheduledTaskTrigger -Daily -At 07:00) -Settings (New-ScheduledTaskSettingsSet -StartWhenAvailable -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -DontStopOnIdleEnd -ExecutionTimeLimit (New-TimeSpan -Hours 2) -MultipleInstances IgnoreNew)"
2020-06-10 08:52:19.509   Process exit code: 1
2020-06-10 08:52:19.511   -- Run entry --
2020-06-10 08:52:19.511   Run as: Current user
2020-06-10 08:52:19.511   Type: Exec
2020-06-10 08:52:19.511   Filename: wscript
2020-06-10 08:52:19.511   Parameters: "C:\Smartclient_MH_LIB\UUUpdater\Mediahuis_Smartclient_Components_Updater.vbs"
2020-06-10 08:57:47.994   Process exit code: 1
2020-06-10 08:57:47.996   -- Run entry --
2020-06-10 08:57:47.996   Run as: Current user
2020-06-10 08:57:47.996   Type: Exec
2020-06-10 08:57:47.996   Filename: NNNotepad
2020-06-10 08:57:47.997   Exception message:
2020-06-10 08:57:47.997   Message box (OK):
                          Unable to execute file:
                          NNNotepad

                          CreateProcess failed; code 2.
                          The system cannot find the file specified.
2020-06-10 08:57:50.009   User chose OK.

那么我应该从哪里得到它才能处理这些命令的返回码呢?如何指定 [Run] 行中的哪些返回代码应该被视为致命的,哪些不是?我怎么抓到他们?我知道我可能需要编写 [Code] 块,也许使用Exec?但是如何从 [Run] 行触发它们?使用Check还是其他?

有人可以举例说明如何从 Powershell 或 Wscript 命令捕获返回代码,以及如何抛出一个操纵安装程序行为的消息框(例如,如果单击 Abort 则退出,如果单击 Ignore 则继续)?

如果出现问题,您如何操作设置本身的退出代码?或者这是一个很大的禁忌?

我阅读了有关 Windows 进程退出代码的内容,这些代码与 Pascal 脚本中的返回代码不同。这让我很困惑。有人可以解释吗?

我一直在研究许多示例和类似主题,但实际上找不到一个有用的案例,我可以对其进行编辑以满足我的需要。

感谢您阅读本文以及您可以提供的任何帮助/见解。

编辑 2020/06/16

抱歉耽搁了。同时这个话题已经结束,但我想让你知道我最终是如何解决它的,我很感激你提供的帮助。通过 Martin Prikryl 提供的建议和一些额外的搜索,我能够达到我的目标:编写一个 [Code] 块,它可以让我执行额外的任务,捕获返回代码并在我愿意的情况下覆盖设置退出代码。我将在下面为需要类似解决方案的任何人发布我的通用代码示例。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; // Example - Run additional actions purely in the [Code] block during the ssPostInstall step (executed after the [Run] block) and use ExitCode to modify the default exit code of the setup
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[Tasks]
Name: "runscript"; Description: "Run a script"

[Code]
// Start with exmpty exit code, can be used to override setup exit code with GetCustomSetupExitCode
var
  ExitCode: Integer;

// Show infinite progress bar while waiting
procedure SetMarqueeProgress(Marquee: Boolean);
begin
  if Marquee then
  begin
    WizardForm.ProgressGauge.Style := npbstMarquee;
  end
    else
  begin
    WizardForm.ProgressGauge.Style := npbstNormal;
  end;
end;

// Run post-installation commands
procedure CurStepChanged(CurStep: TSetupStep);
var
  ResultCode: Integer;
  ProgramNAme: String;
  ProgramArguments: String;
begin
  if CurStep = ssPostInstall then
  begin
    // Change progressbar
    SetMarqueeProgress(True);

    // Run script if task is selected
    if IsTaskSelected('runscript') then
    begin
      WizardForm.StatusLabel.Caption := 'Running script. This may take a few minutes...';
      ProgramName := 'wscript';
      ProgramArguments := ExpandConstant('{sd}\Smartclient_MH_LIB') + '\script\{#MyAppUpdateScript}';
      Log('Running ' + ProgramName + ' ' +  ProgramArguments);
      if Exec(ProgramName, ProgramArguments, '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
      begin
        Log('ResultCode = ' + IntToStr(ResultCode) + '.');
        if ResultCode = 0 then
        begin
          Log('Setup successfully ran the script.')
        end
          else
        begin
          Log('Setup failed to run the script.');
          ExitCode := ExitCode + 1;
        end;
      end;
    end
      else
    begin
      Log('Skipping update because task "update" is not selected.');
    end;

    // Change progressbar
    SetMarqueeProgress(False);
  end;
end;

// Override setup exit code
function GetCustomSetupExitCode: Integer;
begin
  if ExitCode <> 0 then
  begin
    Log('Returning custom exit code ' + IntToStr(ExitCode));
  end;
  Result := ExitCode;
end;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

标签: inno-setup

解决方案


推荐阅读