I'm trying to create a post install configuration page in my nsis script using nsDialogs. My script for gathering the input and executing the configuration works however I'm never presented with a finish/close/exit button after I'm done. Currently my pages declaration looks like:
Page directory
Page instfiles
Page custom nsDialogsPage nsDialogsPageLeave
How can I get a finish/exit/done button to show after nsDialogsPageLeave executes?
The classic NSIS UI does not have a finish page, the instfiles page is usually the last page and it will show a "finish button" after all the sections have executed. You can set the text of any button to the same string with SendMessage $hwndButton ${WM_SETTEXT} 0 "STR:$(^CloseBtn)" if you want to provide your own finish page.
Most installers request the required information before the instfiles page, if you cannot do this then you might want to use the Modern UI, it will provide a finish page for you:
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
Page custom nsDialogsPage nsDialogsPageLeave
!insertmacro MUI_PAGE_FINISH
It was a little unclear to me if you wanted two pages; a input page and then a finish page or a combined input/finish page. A combined page is a little weird but it is possible:
!define AppName "Test"
Name "${AppName}"
Outfile "${AppName} setup.exe"
InstallDir $temp
!include LogicLib.nsh
!include WinMessages.nsh
!include nsDialogs.nsh
Var MyEndConfigPageStage
Page Directory
Page InstFiles
Page Custom MyEndConfigPageCreate MyEndConfigPageLeave /EnableCancel
Function MyEndConfigPageCreate
StrCpy $MyEndConfigPageStage 0
GetDlgItem $0 $hwndparent 1
SendMessage $0 ${WM_SETTEXT} 0 "STR:&Apply"
nsDialogs::Create 1018
Pop $0
${NSD_CreateCheckBox} 0 13u 100% -13u "FooBar"
Pop $1
nsDialogs::Show
FunctionEnd
Function MyEndConfigPageLeave
${If} $MyEndConfigPageStage > 0
Return
${EndIf}
${NSD_GetState} $1 $2
ClearErrors
WriteIniStr "$instdir\settings.ini" Dummy "FooBar" $2
${If} ${Errors}
MessageBox mb_iconstop "Unable to apply settings!"
Abort
${EndIf}
IntOp $MyEndConfigPageStage $MyEndConfigPageStage + 1
GetDlgItem $0 $hwndparent 1
SendMessage $0 ${WM_SETTEXT} 0 "STR:$(^CloseBtn)"
GetDlgItem $0 $hwndparent 2
EnableWindow $0 0 ;Disable cancel
EnableWindow $1 0 ;Disable the checkbox
Abort
FunctionEnd
Section
SectionEnd
Related
I'm writing an NSIS script, in this using some sections to execute EXE files. on depending output, I need to go back from the section to other custom pages but here nsis is moving to another section even though keeping of NSD_OnBack function or just calling the particular function
I have tried below 2 methods.
${NSD_OnBack} "callbackfunction"
call callbackfunction
//Section started
Section "validation" VALIDATION
DetailPrint "Executing Validation"
File "Folder_name\Validation.exe"
nsExec::Exec '"$INSTDIR\Validation.exe" $arg1 $arg2 $arg3'
IfFileExists "$INSTDIR\Output.txt" pass fail
pass:
FileOpen $chk "$INSTDIR\Output.txt" r
FileRead $chk $1
MessageBox MB_OK|MB_ICONSTOP "Validation_Output : in 1 $1"
Push $1
Push "true"
Call StrContains
Pop $3
${If} $3 == "true"
call someotherfunction
${ELSE}
goto fail
${ENDIF}
FileClose $chk
Delete $chk
fail:
MessageBox MB_OK|MB_ICONSTOP "fail"
//Here this call is not working
${NSD_OnBack} "callbackfunction"
SectionEnd
Function callbackfunction
GetDlgItem $0 $HWNDPARENT 2
${IF} $portalname == "centralised"
${IF} $username == ""
call CentralisedPage
${ENDIF}
${ELSE}
${IF} $username == ""
call SetCustom
${ENDIF}
${ENDIF}
Functionend
I am expecting to move other page based on EXE results.
${NSD_OnBack} is a callback for nsDialogs custom pages and it is invoked when the user presses the back button on that page, it is not relevant here.
Ideally you should collect all information before you get to the InstFiles page but if you can't do that then I would recommend that you just show a custom page after the InstFiles page if required.
If you absolutely need to execute sections multiple times you can use more than one InstFiles page:
!include LogicLib.nsh
!include WinMessages.nsh
!include nsDialogs.nsh
!include Sections.nsh
!include MUI2.nsh
!insertmacro MUI_PAGE_COMPONENTS
!define MUI_PAGE_CUSTOMFUNCTION_PRE Init1stStage
!insertmacro MUI_PAGE_INSTFILES
Page Custom MyCustomPageCreate
!define MUI_PAGE_CUSTOMFUNCTION_PRE Init2ndStage
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_LANGUAGE English
Var Needs2ndStage
Section "1st stage" SID_1
DetailPrint "1st stage"
MessageBox mb_yesno "Needs 2nd stage?" IDNO nope
StrCpy $Needs2ndStage 1
nope:
SectionEnd
Section "-2nd stage" SID_2
DetailPrint "2nd stage"
SectionEnd
Function Init1stStage
!insertmacro UnselectSection ${SID_2}
FunctionEnd
Function Init2ndStage
!insertmacro UnselectSection ${SID_1}
${IfThen} $Needs2ndStage = 0 ${|} Abort ${|}
FunctionEnd
Function MyCustomPageCreate
${IfThen} $Needs2ndStage = 0 ${|} Abort ${|}
!insertmacro SelectSection ${SID_2}
GetDlgItem $0 $hWndParent 1
SendMessage $0 ${WM_SETTEXT} "" "STR:C&ontinue"
GetDlgItem $0 $hWndParent 3
ShowWindow $0 0 ; Hide back
GetDlgItem $0 $hWndParent 2
EnableWindow $0 0 ; Disable cancel
!insertmacro MUI_HEADER_TEXT "Blah" "Blah blah blah"
nsDialogs::Create 1018
Pop $0
${NSD_CreateLabel} 0 0 100% 12u "Enter blah blah before you can enter the 2nd stage"
Pop $0
nsDialogs::Show
FunctionEnd
Is there a way to make the NSIS installer skip certain dialogs?
It has these command-line arguments,
/S, /NCRC and /D=dir
Although /S and /NCRC can used for silent and unattended modes, is there are command-line arguments to make the installer skip certain dialogs in the installer and show the rest of the dialog? For example. skip the Welcome dialog and the next two dialogs and go to the fourth one.
/S, /NCRC and /D= are the only installer parameters with built-in support, anything else you have to handle yourself.
Pages can be skipped by calling Abort in the page pre callback. It is also possible to jump forward a specific number of pages. The GetOptions macro can be used to parse the command line.
OutFile Test.exe
RequestExecutionLevel user
InstallDir $Temp
!include LogicLib.nsh
!include FileFunc.nsh
Page License LicPre
Page Components CmpPre
Page Directory "" DiShow
Page InstFiles
Var SkippedL
Var SkippedC
!macro AbortIfCmdlineParam Switch Var
${GetParameters} $0
ClearErrors
${GetOptions} $0 "${Switch}" $0
${IfNot} ${Errors}
${If} ${Var} = 0
StrCpy ${Var} 1
Abort
${EndIf}
${EndIf}
!macroend
Function LicPre
!insertmacro AbortIfCmdlineParam "/SkipL" $SkippedL
FunctionEnd
Function CmpPre
!insertmacro AbortIfCmdlineParam "/SkipC" $SkippedC
FunctionEnd
Function DiShow
# Disable back button if both pages skipped, this is optional
${If} $SkippedL <> 0
${AndIf} $SkippedC <> 0
GetDlgItem $0 $hwndparent 3
EnableWindow $0 0
${EndIf}
FunctionEnd
Section
SectionEnd
Run as Test /SkipL /SkipC to skip both.
Or:
OutFile Test.exe
RequestExecutionLevel user
InstallDir $Temp
!include LogicLib.nsh
!include FileFunc.nsh
Page License "" LicShow
Page Components
Page Directory
Page InstFiles
Function LicShow
Var /Global HasSkipped
${GetParameters} $0
ClearErrors
${GetOptions} $0 "/Skip=" $0
${IfNot} ${Errors}
${AndIf} $0 < 4 ; Don't let user skip InstFiles
${AndIf} $HasSkipped = 0
StrCpy $HasSkipped 1
SendMessage $HWNDPARENT 0x408 $0 ""
${EndIf}
FunctionEnd
Section
SectionEnd
...and run as Test /Skip=2.
I want to create an installer that downloads a file without freezing the UI using the inetc plugin. My question is that possible without using the ExecDos::Exec with the /ASYNC flag and then ExecDos::Wait.
In addition , i do not want installation page in my installer.
Here is my code:
!macro DOWNLOAD_PAGE
Function myTimer
${If} $0 == "OK"
${NSD_KillTimer} myTimer
SendMessage $hPBar ${PBM_SETRANGE32} 0 100
SendMessage $hPBar ${PBM_SETPOS} 100 0
Return
${EndIf}
SendMessage $hPBar ${PBM_SETRANGE32} 0 100
SendMessage $hPBar ${PBM_SETPOS} 50 0
FunctionEnd
function Page1
nsDialogs::Create 1018
Pop $Dialog
${NSD_CreateLabel} 0 0 100% 50% "Starting download..."
Pop $hInfo
${NSD_CreateProgressBar} 0 55% 100% 10u ""
Pop $hPBar
${NSD_CreateTimer} myTimer 1000
inetc::get /silent "$URL\skype.exe" "$EXEDIR\skype.exe" /end
Pop $0
nsDialogs::Show
functionEnd
function Page2
functionEnd
Page Custom Page1 Page2
!macroend
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "${NSISDIR}\Docs\Modern UI\License.txt"
!insertmacro DOWNLOAD_PAGE
!insertmacro MUI_PAGE_FINISH
Or the only option i have is using the ExecDos::Exec with the /ASYNC flag?
Perhaps, a solution it is to create another nsis installer that does the download?
Performing a long operation between nsDialogs::Create and nsDialogs::Show will hang the UI.
The easy solution is to download in a Section because those are executed in a different thread. You are supposed to perform most of your tasks in a Section.
If you insist on downloading something on a custom page then you can use the InetBgDL plug-in:
!include nsDialogs.nsh
!include LogicLib.nsh
Page Custom Page1
Var hInfo
Function Page1
nsDialogs::Create 1018
Pop $0
${NSD_CreateLabel} 0 0 100% 50% "Starting download..."
Pop $hInfo
InitPluginsDir
INetBgDl::Get "https://example.com/file.exe" "$PluginsDir\file.exe" /end
${NSD_CreateTimer} myTimer 1000
nsDialogs::Show
${NSD_KillTimer} myTimer
FunctionEnd
Function myTimer
InetBgDL::GetStats
${NSD_SetText} $hInfo "Status=$0$\nCompleted files=$1$\nDownloaded $3 of $4 bytes"
${If} $0 = 0 ; HTTP status code or 0 if completed without errors
${NSD_KillTimer} myTimer
MessageBox mb_ok Done
${EndIf}
FunctionEnd
As a follow-up to this answer, I'm trying to add the link after issuing Abort command, but for some reason it does not appear, no trace of it when viewed in Spy++.
The idea is to add the link above the progress bar, but somehow the macro does not work. Is there a reason for this that I'm missing and is it possible to add that link after calling Abort? I've read somewhere that Abort command can have different effect so I'm guessing this is one of it.
I've tried to make this sample script as concise as best I can and would greatly appreciate any help as I'm still learning NSIS.
!include "MUI2.nsh"
;--------------------------------
;General
ShowInstDetails hide
SetCompressor /SOLID lzma
;Request application privileges for Windows Vista
RequestExecutionLevel user
;--------------------------------
;Interface Configuration
!define MUI_ABORTWARNING
!define MANUAL_DOWNLOAD_TEXT "Automatic download not working? Click here to download manually."
;--------------------------------
;Macros
!macro AddDownloadLink yCoord
FindWindow $0 "#32770" "" $HWNDPARENT ; Find the inner dialog
System::Call 'USER32::CreateWindowEx(i0, t "STATIC", t "${MANUAL_DOWNLOAD_TEXT}", i${WS_CHILD}|${WS_VISIBLE}|${SS_NOTIFY}, i 1, i ${yCoord}, i 500, i 50, p $0, i 0x666, p 0, p 0)p.s'
Pop $0
SetCtlColors $0 0000ff transparent
CreateFont $1 "$(^Font)" "$(^FontSize)" "400" /UNDERLINE
SendMessage $0 ${WM_SETFONT} $1 1
GetFunctionAddress $1 fnLinkClicked
ButtonEvent::AddEventHandler 0x666 $1
!macroend
;--------------------------------
;Pages
!insertmacro MUI_PAGE_INSTFILES
;--------------------------------
;Languages
!insertmacro MUI_LANGUAGE "English"
;--------------------------------
;Installer Sections
Section
Var /global Filename
StrCpy $Filename "test100Mb.db"
Var /global DownloadUrl
StrCpy $DownloadUrl "http://speedtest.ftp.otenet.gr/files/$Filename"
!insertmacro AddDownloadLink 70
inetc::get /caption "Downloading package" $DownloadUrl "$Filename" /end
Pop $R0 ;Get the return value
StrCmp $R0 "OK" 0 dlfailed
Goto quit
dlfailed:
DetailPrint "Download failed: $R0 $DownloadUrl"
SetDetailsView show
Abort
!insertmacro AddDownloadLink 1
quit:
Quit
SectionEnd
Function fnLinkClicked
ExecShell "open" "$DownloadUrl"
FunctionEnd
Abort stops executing the section(s) code, you must do whatever you need to do before calling Abort.
Adding controls in a section can be problematic because it executes on a different thread and windows are tied to the thread that created them. If you need the window to stick around longer than the install thread you can create it as a hidden window in the instfiles page show callback and simply call ShowWindow in the section when you need to display it...
I'm trying to create a downloader that also has a "Download manually" link, but the link does not seem to show.
I tried to follow instructions from this post but can't seem to make it work.
I'm copying the script here in case anyone can point out what I might be missing - I'm a noob in NSIS scripting, sorry.
!include "MUI2.nsh"
!define NAME "instfileslink"
Name "${NAME}"
OutFile "${NAME}.exe"
!define MUI_PAGE_CUSTOMFUNCTION_SHOW MyInstFilesShow
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Var hCtl_test_Link1
Section
Section
inetc::get /caption "Downloading package" "http://speedtest.ftp.otenet.gr/files/test100Mb.db" "test100Mb.db" /end
Pop $R0
StrCmp $R0 "OK" 0 dlfailed
Quit
dlfailed:
DetailPrint "Download failed: $R0"
Abort
SectionEnd
Function fnLinkClicked
ExecShell "open" "http://speedtest.ftp.otenet.gr/files/test100Mb.db"
FunctionEnd
Function MyInstFilesShow
${NSD_CreateLink} 120u 175u 100% 10u "Download manually"
Pop $hCtl_test_Link1
${NSD_OnClick} $hCtl_test_Link1 fnLinkClicked
FunctionEnd
You cannot use NSDialogs controls (${NSD_Create*}) outside a NSDialogs dialog!
You can use ChangeUI/MUI_UI to add controls to a built-in page or you can add the dynamically at run-time by manually creating a window. You need to use the ButtonEvent plug-in to catch the click events:
!include "MUI2.nsh"
!define MUI_PAGE_CUSTOMFUNCTION_SHOW MyInstFilesShow
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
!include nsDialogs.nsh ; For style defines
ShowInstDetails hide
Function MyInstFilesShow
FindWindow $0 "#32770" "" $HWNDPARENT ; Find the inner dialog
System::Call 'USER32::CreateWindowEx(i0, t "STATIC", t "Download manually", i${WS_CHILD}|${WS_VISIBLE}|${SS_NOTIFY}, i 100, i 200, i 300, i 50, p $0, i 0x666, p 0, p 0)p.s'
Pop $0
SetCtlColors $0 0000ff transparent
SendMessage $hwndparent ${WM_GETFONT} 0 0 $1
SendMessage $0 ${WM_SETFONT} $1 1
GetFunctionAddress $1 fnLinkClicked
ButtonEvent::AddEventHandler 0x666 $1
FunctionEnd
Function fnLinkClicked
ExecShell "open" "http://speedtest.ftp.otenet.gr/files/test100Mb.db"
FunctionEnd