NSIS 中止和错误级别

Posted

技术标签:

【中文标题】NSIS 中止和错误级别【英文标题】:NSIS Abort and errorlevel 【发布时间】:2017-06-27 15:47:44 【问题描述】:

我正在使用 NSIS 构建一个简单的安装程序,并希望在批处理脚本中以静默模式运行它,最后我会像这样检查 ERRORLEVEL:

REM a simple test
REM get into folder and run the installer
cd /d my_installer_path 
my_installer_made_with_nsis.exe /S
if %ERRORLEVEL% NEQ 0 echo something has gone wrong

现在,my_installer_made_with_nsis.exe 似乎总是返回 %ERRORLEVEL% 0 ,即使在 nsi 代码中我明确设置了错误级别并使用 Abort 退出。

在我的 nsi 脚本中,我使用了类似的 ErrorHandling 函数

Function ErrorHandler
IfSilent +2 0
MessageBox MB_ICONSTOP "$err_msg"

DetailPrint "$err_msg"
SetErrorlevel 5 ; <---- APPARENTLY DOES NOT WORK
Abort
FunctionEnd

然后,在我的代码中,我这样调用错误处理程序:

...
StrCpy $err_msg "An exception occurred: blah blah"
Call ErrorHandler

我希望在 cmd shell 外部 %ERRORLEVEL% 为 5,但它始终为 0。

也许我弄错了 NSIS 中 ErrorLevel 的整个概念,但在这种情况下,有没有办法从命令 shell 中检索我的安装程序的退出代码?

【问题讨论】:

你是如何开始这个过程的? 【参考方案1】:

SetErrorlevel 工作正常,这意味着它设置了进程的退出代码。 %ERRORLEVEL% 不一定是子进程的退出代码,尤其是在调用 GUI 进程时。你的问题是你的批处理文件/cmd.exe,而不是 NSIS。

Function MyAbortFunction
SetErrorlevel 5
Abort
FunctionEnd

Section
System::Call 'Kernel32::GetEnvironmentVariable(t "TestAbort", p 0, i0)i.r0'
$If $0 = 0
    System::Call 'Kernel32::SetEnvironmentVariable(t "TestAbort", t "1")'
    ExecWait '"$ExePath"' $0 ; Run the test instance of our self
    MessageBox MB_OK "Exit code = $0" ; This will be 5
    SetErrorlevel $0 ; Make the parent use the same code in case you are testing in cmd.exe
$Else
    Call MyAbortFunction
$EndIf
SectionEnd

在 cmd.exe 中可以正常工作:

start "" /WAIT "c:\my\path\to\Test.exe"
echo %errorlevel%

【讨论】:

谢谢。我稍微编辑了这个问题,只是为了更清楚地了解我如何启动安装程序(确实很简单)。在你的帮助下,我现在可能知道出了什么问题。我“直接”调用安装程序 exe,没有
start /wait
。但由于 NSIS 将安装程序构建为“非控制台应用程序”,我应该选择
start /wait
(也是因为否则脚本将不会停止)。我会试试的。
【参考方案2】:

nsi 脚本没有问题

解决办法是: 在批处理脚本中运行安装程序 start /wait

就这么简单,但对于 NSIS 的初学者来说并不那么明显。

如果您必须等待安装程序继续执行批处理脚本,则使用start /wait 是必要的,但一开始您可能会错过这一点,并且在谈到 ERRORLEVEL 时也会错过效果。

NSIS 手册中有很多很好的运行静默卸载程序的示例http://nsis.sourceforge.net/Docs/Chapter4.html#silent

但它没有提到start /wait的需要

如果以手动为例:

 foo.exe /S /D=C:\Program Files\Foo

(假设 foo 非常简单,并且为了测试而 FAST

当您在 cmd shell 中运行该命令时,一开始您无法意识到 shell 没有等待。然后,如果您检查 ERRORLEVEL,您可能会感到惊讶(就像我一样)

如果您想在交互模式下运行 foo.exe 时测试 ERRORLEVEL,可能会发生同样的事情。您无法意识到 foo 与外壳“分离”。在这种情况下检查 shell %ERRORLEVEL% 是没有用的。

最后你发现有人建议非控制台应用程序必须使用 start /wait

http://forums.winamp.com/showpost.php?p=2530597&postcount=2

所以你应该改用这个命令行:

start /wait foo.exe /S /D=C:\Program Files\Foo`

【讨论】:

以上是关于NSIS 中止和错误级别的主要内容,如果未能解决你的问题,请参考以下文章

NSIS 卸载程序权限级别

管理员级别的 nsis 安装程序需要为非特权用户创建图标

bug的严重级别和优先级

精通Java事务编程-弱隔离级别之快照隔离和可重复读

精通Java事务编程-弱隔离级别之快照隔离和可重复读

错误处理