NSIS silent install ( started via code )

匿名 (未验证) 提交于 2019-12-03 08:30:34

问题:

I'm trying to build an NSIS installer that will do the following:

1 When run normaly it will install the application with a installer with the usual choices.

2 When the installer is run with /S switch it silent installs, it's ok if it shows UI. But it should be automatic.

It seems to me that the installer "works", as it runs and then correctly starts the application again. But it has not updated anything, it's almost as if it runs, but does not copy any files.

When it's a silent install, it's started by the following code ( Application updates itself)

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

NSIS script main ( I can post support scripts for NSIS that are custom if ppl desire )

; 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

回答1:

StrCmp $0 1 0 +3 is wrong, it should be +2 (+3 in this example is probably undefined behavior since you are skipping the hidden return instruction).

Using relative jumps is error prone, you should use a label or rewrite it using the logic lib:

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

But putting the silent install logic in a separate function doubles your work when the normal install logic is almost equal. You should be able to remove the SilentInstall function and just use a hidden section to execute during silent installs:

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

It is hard to say why your files are not updated, but if you use shared code you can run it without /S and check the detail log. My only guess is that InstallDirRegKey is picking up a non default installdir and you are looking at the wrong files. You can Process Monitor to monitor the install.


Your code has some other unrelated issues:

  • RequestExecutionLevel admin is not enough, you need to deal with NT5 and NT6 with UAC off (UserInfo::GetAccountType)
  • You don't have to specify the shortcut icon when the icon is the same as the target program
  • You should quote the path when calling Exec: Exec '"$instdir\${_AppExe}"'
  • Mixing UAC/runas/RequestExecutionLevel admin with Exec is problematic since you can end up running the program as the wrong user.


回答2:

This is a tricky one. I am using the same approach to update an application of mine, calling an NSIS installer silently. In my case, the problem did not lie in the NSIS script, it was that I was using the WebClient class to download a zip file containing my installer to the temp directory, and subsequently extracting it there, and running it from there. The problem is that the ZipFile class generates an exception if the extracted setup file exists, and hence the old installer persists, and nothing except the uninstall executable is updated in the program directory.

For me, the solution was to clean up the old zip and exe files before downloading the new ones (in 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


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!