如何在 NSIS 中获得 VC++ 2005 的正确 return value/status

How to get the correct return value/status of VC++ 2005 in NSIS

我想用 NSIS 静默安装 Visual C++ Redistributable Packages for Visual Studio 2013

但是,没有返回正确的退出代码。我测试了几种类型的变体。我想到的最好的是:

DetailPrint "Installing VC++ 2005"
    File "${STOCKINPUTFOLDER}\bin\Debug\vcredist_x86.EXE"
    ClearErrors
    ExecWait "$OUTDIR\vcredist_x86.EXE /q:a /c:$\"msiexec /i vcredist.msi /qb /norestart$\"" [=13=] ; also can use /qn 

    ;do not delete the file out-rightly so that evaluation of IfErrors below is clean           
    IfErrors execError noError

    execError:
        Goto ShortEndInstall

    ShortEndInstall:
        MessageBox MB_OK|MB_ICONEXCLAMATION "ShortEndInstall"
        Delete "$OUTDIR\vcredist_x86.EXE" ;we did not delete the file outrightly so that evaluation of IfErrors is clean
        Quit

    noError:
        ${If} [=13=] != 0
            MessageBox MB_OK|MB_ICONEXCLAMATION "You did not complete the installation of the VC++ 2005 re-distributable. Installation will now abort. Return code [=13=]"
            Goto ShortEndInstall
        ${EndIf}

        MessageBox MB_OK|MB_ICONEXCLAMATION "No error"
        Delete "$OUTDIR\vcredist_x86.EXE" ;we did not delete the file outrightly so that evaluation of IfErrors is clean

但是当我故意点击VC++2005安装的"Cancel"按钮时,NSIS仍然认为安装成功(我在指令MessageBox MB_OK|MB_ICONEXCLAMATION "No error")

如何准确正确地获取返回的错误信息(例如我自己"Cancel"安装时)?

编辑:

在@Anders 的帮助下,我现在有以下内容,但仍然失败(即 not installed 即使 VC++ 2005 安装已完成。我还尝试了不同的命令行选项安装 VC++2005)

!include LogicLib.nsh
!include WordFunc.nsh

!define VERSION "8.1.0.0"
!define SHORTVERSION "8.1"
!define NAME "SchoolServer MainHost"
!define SHARPDEVFOLDER "..\..\..\.."
!define STOCKINPUTFOLDER "${SHARPDEVFOLDER}\SchoolServer_100\SS-Server"
!define PARENTSTOCKFOLDER "${SHARPDEVFOLDER}\SchoolServer_100"

!define MSVC2005_X86REDIST_PRODUCTCODE {A49F249F-0C91-497F-86DF-B2585E8E76B7}
!define MSVC2005_X86REDIST_PRODUCTCODE_SP1 {7299052B-02A4-4627-81F2-1818DA5D550D}
!define MSVC2005_X86REDIST_PRODUCTCODE_SP1_UP {837B34E3-7C30-493C-8F6A-2B0F04E2912C}
!define INSTALLSTATE_DEFAULT 5

!define MACRO_check_successful_install "!insertmacro check_vc_install"
!define MACRO_check_successful_install_exclusive_2005 "!insertmacro check_vc_install_exclusive_2005"

Var function_call_return
Var tested_vc_key

!macro check_vc_install install_key
  DetailPrint "Copying  ${install_key} to tested_vc_key"
  StrCpy $tested_vc_key ${install_key}
  call check_vc_install_normal
!macroend

!macro check_vc_install_exclusive_2005 install_key
  StrCpy $tested_vc_key ${install_key}
  call check_vc_install_exclusive_2005
!macroend

OutFile "${NAME} Lite Installer - ${SHORTVERSION}.exe"

#Sections
Section "Installation"
    SetShellVarContext all
    SetOutPath "$INSTDIR"
    SetRebootFlag false
    DetailPrint "Installing VC++ 2005"
    File "${STOCKINPUTFOLDER}\bin\Debug\vcredist_x86.EXE"
    ClearErrors
    ExecWait "$OUTDIR\vcredist_x86.EXE /q:a /c:$\"msiexec /i vcredist.msi /qb /norestart$\" " [=14=] ; also can use /qn 

    ;we will not delete the file out-rightly so that evaluation of IfErrors below is clean      
    IfErrors execError noError

    execError:
        MessageBox MB_OK|MB_ICONEXCLAMATION "First line error!"
        Goto ShortEndInstall

    ShortEndInstall:
    MessageBox MB_OK|MB_ICONEXCLAMATION "Installation of Microsoft Visual C++ 2005 runtime libraries failed!"
    Delete "$OUTDIR\vcredist_x86.EXE" ;we did not delete the file outrightly so that evaluation of IfErrors is clean
    ;Quit
    Return

    noError:
    ;if no error, then check the exit code (https://sourceforge.net/p/nsis/mailman/message/22965694/ [use timemachine if 404 error. Page was accessed June 26, 2017])
    ${If} [=14=] != 0
        MessageBox MB_OK|MB_ICONEXCLAMATION "You did not complete the installation of the VC++ 2005 re-distributable. Installation will now abort. [Error [=14=]]"
        Goto ShortEndInstall
    ${EndIf}

    ClearErrors
    ${MACRO_check_successful_install} ${MSVC2005_X86REDIST_PRODUCTCODE}
    ${If} $function_call_return == "installed"
        Goto ContinueInstallation
    ${Else}
        ${MACRO_check_successful_install} ${MSVC2005_X86REDIST_PRODUCTCODE_SP1}
        ${If} $function_call_return == "installed"
            Goto ContinueInstallation
        ${Else}
            ${MACRO_check_successful_install} ${MSVC2005_X86REDIST_PRODUCTCODE_SP1_UP}
            ${If} $function_call_return == "installed"
                Goto ContinueInstallation
            ${Else}
                ${MACRO_check_successful_install_exclusive_2005} ${MSVC2005_X86REDIST_PRODUCTCODE}
                ${If} $function_call_return == "installed"
                    Goto ContinueInstallation
                ${Else}
                    ${MACRO_check_successful_install_exclusive_2005} ${MSVC2005_X86REDIST_PRODUCTCODE_SP1}
                    ${If} $function_call_return == "installed"
                        Goto ContinueInstallation
                    ${Else}
                        ${MACRO_check_successful_install_exclusive_2005} ${MSVC2005_X86REDIST_PRODUCTCODE_SP1_UP}
                        ${If} $function_call_return == "installed"
                            Goto ContinueInstallation
                        ${Else}
                            DetailPrint "Quiting... [Returned value: $function_call_return]"
                            Goto ShortEndInstall
                        ${EndIf}
                    ${EndIf}
                ${EndIf}
            ${EndIf}
        ${EndIf}
    ${EndIf}

    ContinueInstallation:

    Delete "$OUTDIR\vcredist_x86.EXE" ;we did not delete the file outrightly so that evaluation of IfErrors is clean

    CreateDirectory  "$INSTDIR\idcard"
    File /r "${STOCKINPUTFOLDER}\bin\Debug\idcard" 
SectionEnd


Function check_vc_install_normal
    DetailPrint "check_vc_install_normal: Checking installation of $tested_vc_key"
    System::Call 'MSI::MsiGetProductInfo(t "$tested_vc_key", t "ProductName", t"?"r1, *i${NSIS_MAX_STRLEN})i.r0'
    ClearErrors
    ${If} [=14=] == 0
        DetailPrint "ProductName: "
        System::Call 'MSI::MsiGetProductInfo(t "$tested_vc_key", t "AssignmentType", t"?"r1, *i${NSIS_MAX_STRLEN})i.r0'
        DetailPrint "AssignmentType: "
        System::Call 'MSI::MsiGetProductInfo(t "$tested_vc_key", t "PackageCode", t"?"r1, *i${NSIS_MAX_STRLEN})i.r0'
        DetailPrint "PackageCode: "
        System::Call 'MSI::MsiGetProductInfo(t "$tested_vc_key", t "VersionString", t"?"r1, *i${NSIS_MAX_STRLEN})i.r0'
        DetailPrint "VersionString: "
        StrCpy $function_call_return "installed"
    ${Else}
        DetailPrint "Not installed [[=14=]] [from check_vc_install_normal]"
        StrCpy $function_call_return "not installed"
    ${EndIf}
FunctionEnd

Function check_vc_install_exclusive_2005
    DetailPrint "check_vc_install_exclusive_2005: Checking special vc2005 installation of $tested_vc_key"
    ClearErrors
    System::Call 'MSI::MsiQueryProductState(t "$tested_vc_key")i.r0'
    ${If} ${INSTALLSTATE_DEFAULT} = [=14=]
        StrCpy $function_call_return "installed"
    ${Else}
        DetailPrint "Not installed [[=14=]] [from check_vc_install_exclusive_2005]"
        StrCpy $function_call_return "not installed"
    ${EndIf}
FunctionEnd

也许 vcredist_x86.exe 没有 return 从 MsiExec 正确输入退出代码?

如果 ExecWait 能够找到并启动进程(IfErrors 是 "false"),那么 NSIS 可以保证 return 从子进程中获得正确的退出代码.

[=13=] != 0 实际上是一个字符串比较,您应该使用 [=14=] <> 0 来比较 32 位数字,但在这种情况下这不是问题。

!include LogicLib.nsh
Section

ExecWait '"cmd" /c exit 0' [=10=]
${If} ${Errors}
${OrIf} [=10=] <> 0
    Abort "Error, child process exited with [=10=]" # Will not abort here
${EndIf}

ExecWait '"cmd" /c exit 1234' [=10=]
${If} ${Errors}
${OrIf} [=10=] <> 0
    Abort "Error, child process exited with [=10=]" # Will abort here
${EndIf}

SectionEnd