Is there a way to link a part of text in DetailPrint in NSIS script to point to a file? - nsis

Example:
DetailPrint "Errors detected running post installation scripts. Click here to view the results."
Clicking on "here" should take user to specific file"

The log window is just a ListView control and it does not support this.
You can display a message to the user:
Section
; Post install steps...
MessageBox MB_YESNO|MB_ICONQUESTION "There was a problem, view results?" /SD IDNO IDNO skipresults
ExecShell "" "$Temp\InstallError.log"
skipresults:
SectionEnd
Or you can display a custom page with a link on it:
!include nsDialogs.nsh
!include LogicLib.nsh
Page Directory
Page InstFiles
Page Custom myPostFailureCreate
Var PostFailure
Function OpenPostReport
ExecShell ...
FunctionEnd
Function myPostFailureCreate
${If} $PostFailure = 0
Abort
${EndIf}
nsDialogs::Create 1018
Pop $0
${NSD_CreateLabel} 5u 0 80% 12u "Install scripts failed!"
Pop $0
${NSD_CreateLink} 5u 13u 80% 12u "View report"
Pop $1
${NSD_OnClick} $1 OpenPostReport
nsDialogs::Show
FunctionEnd
Section
; Post install steps...
${If} ${Errors}
StrCpy $PostFailure 1
${EndIf}
SectionEnd

Related

${NSD_GetText} always returns the empty string

Per the manual, I should be able to get the text of a text control with code like this:
${NSD_GetText} $TextBox $0
MessageBox MB_OK "You typed:$\n$\n$0"
I always get the empty string out of this call. In the code below, the text box shows "correct" but the details always show Contents:; if I comment the call to ${NSD_GetText}, I get Contents: wrong.
!include nsDialogs.nsh
!include LogicLib.nsh
Var Dialog
Var TextBox
Page custom nsDialogsPage nsDialogsPageLeave
Page instfiles
Function nsDialogsPage
StrCpy $0 "wrong"
nsDialogs::Create 1018
Pop $Dialog
${If} $Dialog == error
Abort
${EndIf}
${NSD_CreateText} 0 12u 93% 12u "correct"
Pop $TextBox
nsDialogs::Show
FunctionEnd
Function nsDialogsPageLeave
FunctionEnd
Section
${NSD_GetText} $TextBox $0
DetailPrint "Contents: $0"
SectionEnd
So I thought maybe the control didn't exist when I was trying to print its contents, and tried updating the text as it was typed into the control; that didn't help. It's implausible that NSIS is broken in this way, so what am I doing wrong?
!include nsDialogs.nsh
!include LogicLib.nsh
Var Dialog
Var TextBox
Var Text
Page custom nsDialogsPage nsDialogsPageLeave
Page instfiles
Function nsDialogsPage
StrCpy $0 "wrong"
nsDialogs::Create 1018
Pop $Dialog
${If} $Dialog == error
Abort
${EndIf}
${NSD_CreateText} 0 12u 93% 12u "correct"
Pop $TextBox
${NSD_OnChange} $TextBox UpdateText
nsDialogs::Show
FunctionEnd
Function nsDialogsPageLeave
FunctionEnd
Function UpdateText
${NSD_GetText} $TextBox $Text
FunctionEnd
Section
DetailPrint "Contents: $Text"
SectionEnd
You are correct, the control does not exist in the Section so you have to get the contents while you are on the custom page.
Your second example should work correctly if the user changes the text but not if they don't because the change event would not fire.
You normally just read the content in the page leave callback:
Var Dialog
Var TextBox
Var Text
!include LogicLib.nsh
!include nsDialogs.nsh
Page custom nsDialogsPage nsDialogsPageLeave
Page instfiles
Function nsDialogsPage
nsDialogs::Create 1018
Pop $Dialog
${If} $Dialog == error
Abort
${EndIf}
${NSD_CreateText} 0 12u 93% 12u "correct"
Pop $TextBox
nsDialogs::Show
FunctionEnd
Function nsDialogsPageLeave
${NSD_GetText} $TextBox $Text
FunctionEnd
Section
DetailPrint "Contents: $Text"
SectionEnd

NSIS: How do I allow multiple user choice screens that select the sections to install?

I'm attempting to create an installer that asks the user a series of questions to decide which components to install. Each choice (potentially) influences the available options in later choices (else I would just do a normal components page—I don't want to give the user invalid options).
How do I accomplish such a thing? If I just use the components page, all the options are shown, some combinations of which are completely invalid. I don't want to let the user select those. Is it possible to leave out the components page?
Here's a minimal working example of what I'm trying. (Sorry it's long, I couldn't really simplify the dialog code.)
!include nsDialogs.nsh
!include Sections.nsh
Name "mwe"
OutFile "mwe.exe"
InstallDir C:\mwe
Var hwnd
Var Level1Opt
Page custom SelectLevel1Opt ProcessLevel1
Function SelectLevel1Opt
nsDialogs::Create 1018
pop $hwnd
${NSD_CreateLabel} 0 0 100% 12u "Please select level 1 option"
Pop $hwnd
${NSD_CreateRadioButton} 10% 12u 100% 12u "Level 1 A"
Pop $hwnd
nsDialogs::SetUserData $hwnd "Level 1 A"
${NSD_OnClick} $hwnd SetLevel1
${NSD_CreateRadioButton} 10% 24u 100% 12u "Level 1 B"
Pop $hwnd
nsDialogs::SetUserData $hwnd "Level 1 B"
${NSD_OnClick} $hwnd SetLevel1
nsDialogs::Show
FunctionEnd
Function SetLevel1
Pop $hwnd
nsDialogs::GetUserData $hwnd
Pop $Level1Opt
MessageBox MB_OK "Selected: $Level1Opt"
FunctionEnd
Function ProcessLevel1
${If} $Level1Opt == "Level 1 A"
!insertmacro SelectSection Level1A
${ElseIf} $Level1Opt == "Level 1 B"
!insertmacro SelectSection Level1B
${EndIf}
FunctionEnd
Page directory
Page instfiles
Section ""
MessageBox MB_OK "Common Install"
SectionEnd
Section /o "" Level1A
MessageBox MB_OK "Level 1 A"
SectionEnd
Section /o "" Level1B
MessageBox MB_OK "Level 1 B"
SectionEnd
No matter what I choose, neither Level1A nor Level1B sections get run. The selection from the dialog is correctly detected in the handler and the post function. However, selecting the sections isn't causing them to run. Even if I add a components page, neither of them is selected.
I looked in Selection.nsh, and the example it refers to (one-section.nsi) doesn't really do what I want, because it uses the components page. (I also don't understand quite how it works.)
What am I doing wrong? In what way am I misunderstanding the way NSIS is supposed to work?
As idleberg says, the correct syntax is !insertmacro SelectSection ${Level1A} but you get a warning because the section id is not defined until after its Section instruction in your .nsi. You need to move the functions that use ${Level1A} below the sections in your source code:
!include nsDialogs.nsh
!include Sections.nsh
Page custom SelectLevel1Opt ProcessLevel1
Page instfiles
Section ""
MessageBox MB_OK "Common Install"
SectionEnd
Section /o "a" Level1A
MessageBox MB_OK "Level 1 A"
SectionEnd
Section /o "b" Level1B
MessageBox MB_OK "Level 1 B"
SectionEnd
Var hInnerDialog
Var hL1A
Var hL1B
Function SelectLevel1Opt
nsDialogs::Create 1018
pop $hInnerDialog
${NSD_CreateLabel} 0 0 100% 12u "Please select level 1 option"
Pop $0
${NSD_CreateRadioButton} 10% 12u 100% 12u "Level 1 A"
Pop $hL1A
nsDialogs::SetUserData $hL1A ${Level1A} ; Only used by the generic function
${NSD_CreateRadioButton} 10% 24u 100% 12u "Level 1 B"
Pop $hL1B
nsDialogs::SetUserData $hL1B ${Level1B} ; Only used by the generic function
nsDialogs::Show
FunctionEnd
Function ProcessLevel1
${NSD_GetState} $hL1A $1
${If} $1 <> ${BST_UNCHECKED}
!insertmacro SelectSection ${Level1A}
!insertmacro UnselectSection ${Level1B}
${Else}
!insertmacro SelectSection ${Level1B}
!insertmacro UnselectSection ${Level1A}
${EndIf}
FunctionEnd
The ProcessLevel1 function can also be implemented as a loop if there are many radio buttons:
Function ProcessLevel1
StrCpy $0 ""
loop:
FindWindow $0 "${__NSD_RadioButton_CLASS}" "" $hInnerDialog $0
System::Call "USER32::GetWindowLong(p$0,i${GWL_STYLE})i.r1"
IntOp $1 $1 & ${BS_AUTORADIOBUTTON}
${If} $1 = ${BS_AUTORADIOBUTTON} ; Is it a auto radio button?
nsDialogs::GetUserData $0 ; Get the section id
Pop $2
${NSD_GetState} $0 $1
${If} $1 <> ${BST_UNCHECKED}
!insertmacro SelectSection $2
${Else}
!insertmacro UnselectSection $2
${EndIf}
${EndIf}
IntCmp $0 0 "" loop loop
FunctionEnd

Jump to Next Page

I am trying to jump forward 1 page in my installer. I have a custom page in my NSIS installer. This custom page prompts the user to input a serial number. If they are valid I will jump the installer forward to the next page (the welcome page) if not we remain on the page. I will be jumping to the next page from within both the Initialse and Finalise functions.
Every time I try to jump to the next page the installer just closes. I have tried Abort and Return but both cause the installer to close. I have also trid Call RelGoToPage where $R9 is 1 but this sends the user back the page they are already on, ie, an infinite loop.
Whats going wrong and how can I make my installer jump to the next page.
# Page Definition
Page Custom SerialPageInitialise SerialPageFinalise
# Page Implementation
Function SerialPageInitialise
!insertmacro ValidateSUser
${If} $isValidUser > 0 # If user if valid
Return # Go to next page...Doesn't work just closes the whole installer
#Abort # Doesn't work just closes the whole installer
${EndIf}
FunctionEnd
# For the following function: the message "A" always shows then the installer closes
Function SerialPageFinalise
${NSD_GetText} $SerialEditBx $R9
!insertmacro ValidateUserExpanded "$R9"
${If} $isValidUser > 0 # If user if valid
MessageBox MB_OK "A"
${Else}
MessageBox MB_OK|MB_ICONEXCLAMATION "Authentication Failed. You are not a recognised client."
Abort
${EndIf}
FunctionEnd
Works fine for me:
!include LogicLib.nsh
!include nsDialogs.nsh
var isValidUser
var SerialEditBx
!macro ValidateUserExpanded param
StrCpy $isValidUser 0
${If} ${param} = 666
StrCpy $isValidUser 1
${EndIf}
!macroend
!macro ValidateSUser
MessageBox mb_yesno "ValidateSUser?" IDNO nope
!insertmacro ValidateUserExpanded 666
nope:
!macroend
Function SerialPageInitialise
!insertmacro ValidateSUser
${If} $isValidUser > 0
Abort ; Skip page
${EndIf}
nsDialogs::Create 1018
Pop $0
${NSD_CreateText} 0 13u 50% 13u "667"
Pop $SerialEditBx
nsDialogs::Show
FunctionEnd
Function SerialPageFinalise
${NSD_GetText} $SerialEditBx $R9
!insertmacro ValidateUserExpanded "$R9"
${If} $isValidUser > 0 # If user if valid
MessageBox MB_OK "OK"
${Else}
MessageBox MB_OK|MB_ICONEXCLAMATION "Authentication Failed. You are not a recognised client."
Abort ; Don't allow going to next page
${EndIf}
FunctionEnd
Page Custom SerialPageInitialise SerialPageFinalise
Page InstFiles

How to use REMOVE or REPAIR feature in NSIS script?

I have used nsis script for creating installer.When i run my installer second time with same name,REPAIR and REMOVE should be check and do the corresponding operation.I have find out my application already installed or not using following codes,
Function checkinstall
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\My app" "UninstallString"
IfFileExists $R0 +1 NotInstalled
call nsDialogpage
NotInstalled:
FunctionEnd
Function nsDialogpage
nsDialogs::Create 1018
Pop $Dialog
${If} $Dialog == error
Abort
${EndIf}
${NSD_CreateRadioButton} 0 5u 100% 10u "Repair"
Pop $hwnd
${NSD_AddStyle} $hwnd ${WS_GROUP}
${NSD_OnClick} $hwnd ???
${NSD_CreateRadioButton} 0 25u 100% 56u "Remove"
Pop $hwnd
${NSD_OnClick} $hwnd ???
nsDialogs::Show
If the user select repair button it should overwrites existing installation path else uninstall existing installed and continue with new one.what am i need do to replace the (???) of the above code
page custom checkinstall
!insertmacro MUI_PAGE_DIRECTORY
My next page is Directory selection.so i need to call this page? How to achieve this?
1.How can i call un installer function if the user selects remove button?
Function un.Init, section /o -un.Main UNSEC000,section -un.post UNSE001
these are the un installer funtions.How can i call these functions? i have tried call method but it did not work.
You need to specify a callback function, like in the nsDialogs documentation, look for the nsDialogsPageLeave function in this example:
!include nsDialogs.nsh
!include LogicLib.nsh
Name nsDialogs
OutFile nsDialogs.exe
XPStyle on
Var Dialog
Var Label
Var Text
Page custom nsDialogsPage nsDialogsPageLeave
Page instfiles
Function nsDialogsPage
nsDialogs::Create 1018
Pop $Dialog
${If} $Dialog == error
Abort
${EndIf}
${NSD_CreateLabel} 0 0 100% 12u "Hello, welcome to nsDialogs!"
Pop $Label
${NSD_CreateText} 0 13u 100% -13u "Type something here..."
Pop $Text
${NSD_OnChange} $Text nsDialogsPageTextChange
nsDialogs::Show
FunctionEnd
Function nsDialogsPageLeave
${NSD_GetText} $Text $0
MessageBox MB_OK "You typed:$\n$\n$0"
FunctionEnd
Function nsDialogsPageTextChange
Pop $1 # $1 == $ Text
${NSD_GetText} $Text $0
${If} $0 == "hello"
MessageBox MB_OK "right back at ya!"
${EndIf}
FunctionEnd
Section
DetailPrint "hello world"
SectionEnd

How can I get a finish button after a nsDialogs page

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

Resources