NSIS 中止和错误级别

问题描述 投票:0回答:3

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

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 检索安装程序的退出代码?

windows error-handling installation nsis abort
3个回答
3
投票

SetErrorlevel
工作正常,这意味着它设置了进程的退出代码。
%ERRORLEVEL%
不一定是子进程的退出代码,特别是当您调用 GUI 进程时。你的问题是你的batch-file/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%

0
投票

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 没有等待。然后,如果您检查错误级别,您会感到惊讶(像我一样)

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

最后你发现有人建议必须使用启动/等待非控制台应用程序

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

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

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

0
投票

在PowerShell中,你可以大致这样实现:

$process = Start-Process -FilePath .\foo.exe -ArgumentList "/S" -PassThru
$process.WaitForExit()
$errorlevel = $process.ExitCode
© www.soinside.com 2019 - 2024. All rights reserved.