NSIS静默安装(通过代码启动)

我正在尝试构建一个NSIS安装程序,它将执行以下操作:

1当正常运行时,它将使用具有常规选项的安装程序安装应用程序。

2当使用/ S开关运行安装程序时,它会进行静默安装,如果它显示UI则可以。 但它应该是自动的。

在我看来,安装程序“工作”,因为它运行,然后再次正确启动应用程序。 但它没有更新任何东西,它几乎就像它运行,但不复制任何文件。

当它是静默安装时,它由以下代码启动(应用程序更新自身)

ProcessStartInfo Pro = new ProcessStartInfo(); Pro.Verb = "runas"; Pro.UseShellExecute = true; Pro.FileName = gDownloadedFileName; Pro.Arguments = "/S"; Pro.WindowStyle = ProcessWindowStyle.Normal; Pro.CreateNoWindow = true; 

NSIS脚本主(我可以发布NSIS支持脚本,如果ppl需要自定义)

 ; example2.nsi ; ; This script is based on example1.nsi, but it remember the directory, ; has uninstall support and (optionally) installs start menu shortcuts. ; ; It will install example2.nsi into a directory that the user selects, !include MUI.nsh !include fileassoc.nsh !include Silent.nsh !define _AppName "My application" !define _AppExe "My application.exe" !define _AppVersion "1.0.0.0" ;--------------------------------------------------------------------- Dont edit beloow ; The name of the installer Name "${_AppName}" ; The file to write OutFile "DFOInfo_Setup_beta.exe" ; The default installation directory InstallDir "$PROGRAMFILES\${_AppName}" ; Registry key to check for directory (so if you install again, it will ; overwrite the old one automatically) InstallDirRegKey HKLM "Software\TheXSoft.com\${_AppName}" "Install_Dir" RequestExecutionLevel admin Function .onInit Call GetDotNet Call IsSilent Pop $0 StrCmp $0 1 0 +3 Call SilentInstall FunctionEnd Function GetDotNet IfFileExists "$WINDIR\Microsoft.NET\Framework\v4.0.30319\installUtil.exe" NextStep MessageBox MB_OK|MB_ICONEXCLAMATION "You must have the Microsoft .NET Framework 4.0 Installed to use this application. $\n$\n The installer will now open the Microsft .NET Framework 4.0 webpage$\n$\n$\n$\nRemember this program will not function until you have installed the .NET Framework 4 ( You will get a error message if you try to start it)" ExecShell Open "http://www.microsoft.com/downloads/en/details.aspx?FamilyID=9cfb2d51-5ff4-4491-b0e5-b386f32c0992&displaylang=en" SW_SHOWNORMAL Quit NextStep: FunctionEnd Section SectionEnd ;-------------------------------- ; Pages shown on none silent installer ;!insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_INSTFILES # These indented statements modify settings for MUI_PAGE_FINISH ;If we want to display a run app function !define MUI_FINISHPAGE_NOAUTOCLOSE !define MUI_FINISHPAGE_RUN_TEXT "Run ${_AppName}" !define MUI_FINISHPAGE_RUN_CHECKED !define MUI_FINISHPAGE_RUN "$INSTDIR\${_AppExe}" !insertmacro MUI_PAGE_FINISH !insertmacro MUI_LANGUAGE "English" !insertmacro MUI_LANGUAGE "German" !insertmacro MUI_LANGUAGE "French" UninstPage uninstConfirm UninstPage instfiles ;-------------------------------- ; The stuff to install Section "${_AppName} (required)" SectionIn RO ; Set output path to the installation directory. SetOutPath $INSTDIR ; Put file there File /R "Current\*.*" ; Write the installation path into the registry WriteRegStr HKLM "Software\TheXSoft.com\${_AppName}" "Install_Dir" "$INSTDIR" ; Write the uninstall keys for Windows WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${_AppName}" "DisplayName" "${_AppName} ( Remove only)" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${_AppName}" "UninstallString" '"$INSTDIR\uninstall.exe"' WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${_AppName}" "NoModify" 1 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${_AppName}" "NoRepair" 1 WriteUninstaller "uninstall.exe" SectionEnd ; Optional section (can be disabled by the user) Section "Start Menu Shortcuts" SetShellVarContext all CreateDirectory "$SMPROGRAMS\${_AppName}" CreateShortCut "$SMPROGRAMS\${_AppName}\TheXSoft.com - Software page.url" "$INSTDIR\TheXSoft.com - Software page.url" CreateShortCut "$SMPROGRAMS\${_AppName}\GuildStats.NET - Get the stats for your MMO.url" "$INSTDIR\GuildStats.NET - Get the stats for your MMO.url" CreateShortCut "$SMPROGRAMS\${_AppName}\${_AppName}.lnk" "$INSTDIR\${_AppExe}" "" "$INSTDIR\${_AppExe}" 0 SectionEnd ;-------------------------------- ; Uninstaller Section "Uninstall" ; Remove registry keys DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${_AppName}" DeleteRegKey HKLM "SOFTWARE\${_AppName}" ; Remove files and uninstaller Delete "$INSTDIR\*.exe" Delete $INSTDIR\uninstall.exe ; Remove shortcuts, if any Delete "$SMPROGRAMS\${_AppName}\*.*" ; Remove directories used RMDir "$INSTDIR" SectionEnd ;-------------------------------- ; Silent install logic Function SilentInstall ; Set output path to the installation directory. SetOutPath $INSTDIR ; Put file there File /R "Current\*.*" ; Write the installation path into the registry WriteRegStr HKLM "Software\TheXSoft.com\${_AppName}" "Install_Dir" "$INSTDIR" ; Write the uninstall keys for Windows WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${_AppName}" "DisplayName" "${_AppName} ( Remove only)" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${_AppName}" "UninstallString" '"$INSTDIR\uninstall.exe"' WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${_AppName}" "NoModify" 1 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${_AppName}" "NoRepair" 1 WriteUninstaller "uninstall.exe" SetShellVarContext all CreateDirectory "$SMPROGRAMS\${_AppName}" CreateShortCut "$SMPROGRAMS\${_AppName}\TheXSoft.com - Software page.url" "$INSTDIR\TheXSoft.com - Software page.url" CreateShortCut "$SMPROGRAMS\${_AppName}\GuildStats.NET - Get the stats for your MMO.url" "$INSTDIR\GuildStats.NET - Get the stats for your MMO.url" CreateShortCut "$SMPROGRAMS\${_AppName}\${_AppName}.lnk" "$INSTDIR\${_AppExe}" "" "$INSTDIR\${_AppExe}" 0 Exec ${_AppExe} Quit FunctionEnd 

StrCmp $ 0 1 0 +3是错误的,它应该是+2(在这个例子中+3可能是未定义的行为,因为你正在跳过隐藏的返回指令)。

使用相对跳转很容易出错,您应该使用标签或使用逻辑库重写它:

 !include LogicLib.nsh ... Function .onInit Call GetDotNet ${If} ${Silent} call SilentInstall ${EndIf} FunctionEnd 

但是,当正常安装逻辑几乎相等时,将静默安装逻辑放在一个单独的函数中会使工作量增加一倍。 您应该能够删除SilentInstall函数,并在静默安装期间使用隐藏部分执行:

 Section "${_AppName} (required)" #shared install code SectionEnd Section "Start Menu Shortcuts" #shared startmenu code SectionEnd Section ${If} ${Silent} Exec ${_AppExe} ${EndIf} Section 

很难说为什么你的文件没有更新,但是如果使用共享代码,你可以在没有/ S的情况下运行它并查看详细日志。 我唯一的猜测是,InstallDirRegKey正在选择一个非默认的installdir而你正在查看错误的文件。 您可以使用Process Monitor来监视安装。


您的代码还有其他一些不相关的问题:

  • RequestExecutionLevel admin是不够的,你需要处理NT5和NT6与UAC关闭( UserInfo :: GetAccountType )
  • 当图标与目标程序相同时,您不必指定快捷方式图标
  • 你应该在调用Exec时执行路径: Exec '"$instdir\${_AppExe}"'
  • 将UAC / runas / RequestExecutionLevel管理员与Exec混合是有问题的,因为您最终可能以错误的用户身份运行程序。

这是一个棘手的问题。 我使用相同的方法来更新我的应用程序,默默地调用NSIS安装程序。 在我的情况下,问题不在于NSIS脚本,而是我使用WebClient类将包含我的安装程序的zip文件下载到临时目录,然后在那里将其解压缩,然后从那里运行它。 问题是如果提取的安装文件存在,ZipFile类会生成exception,因此旧的安装程序会保留,并且除了卸载可执行文件之外的任何内容都不会在程序目录中更新。

对我来说,解决方案是在下载新文件之前清理旧的zip和exe文件(在VB.NET中):

  If File.Exists(Path.Combine(Path.GetTempPath(), "Setup.zip")) Then File.Delete(Path.Combine(Path.GetTempPath(), "Setup.zip")) End If If File.Exists(Path.Combine(Path.GetTempPath(), "Setup.exe")) Then File.Delete(Path.Combine(Path.GetTempPath(), "Setup.exe")) End If