NSIS silent install ( started via code )
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 "$SMP开发者_StackOverflow中文版ROGRAMS\${_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 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.
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
精彩评论