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

本文关键字:代码 启动 静默 安装 NSIS | 更新日期: 2023-09-27 17:55:06

我正在尝试构建一个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脚本主(如果ppl愿意,我可以发布自定义的NSIS支持脚本)

; 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

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

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正在挑选一个非默认的安装目录,你正在看错误的文件。您可以使用Process Monitor来监视安装过程。


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

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

这是一个棘手的问题。我使用相同的方法来更新我的应用程序,静默地调用NSIS安装程序。在我的例子中,问题不在于NSIS脚本,而是我使用WebClient类将包含我的安装程序的zip文件下载到临时目录,然后在那里提取它,并从那里运行它。问题是,ZipFile类生成一个异常,如果提取的安装文件存在,因此旧的安装程序仍然存在,除了卸载可执行文件外,程序目录中没有更新任何内容。

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

    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