is there any possibility to show some descriptive text on NSIS installer custom page, but only on mouse hover?
I have the prerequisites check at the beginning of the installer and when one (or more) of the tests fail, appropriate warning message is displayed. It is custom page displayed before whole installation. The problem is, that there are too many messages (in the worst case) and installer page small -- it isn't possible to show all of them without overlaying... So I would like to display only some title (briefly describing the problem) and more detailed information somewhere below in the dedicated area, but only when mouse moved over the brief text. Or, other solution is to create some scrollable area...
But I don't know how to do it in NSIS. I know .onMouseOverSection callback, but AFAIK it can be used only in section selection page.
Is it possible to do it in NSIS page?
Thanks in advance.
I don't think doing this on the instfiles page is a good idea. I would go for a custom page. If you decide to go with the custom page idea, you probably have 3 options:
Create a custom nsis plugin that shows a page in any way you want.
Create a custom page with nsDialogs and handle the mouse messages with the WndSubclass plugin.
Use two component pages and tweak one of them.
The following example uses the 3rd option since it uses only official nsis plugins.
OutFile "$%temp%\test.exe"
Name "Prereq desc"
RequestExecutionLevel user
!include MUI2.nsh
!define MUI_PAGE_HEADER_TEXT "Header blablah"
!define MUI_PAGE_HEADER_SUBTEXT "subheader blablah"
!define MUI_COMPONENTSPAGE_TEXT_TOP "blablah 1"
!define MUI_COMPONENTSPAGE_TEXT_INSTTYPE " "
!define MUI_COMPONENTSPAGE_TEXT_COMPLIST " "
!define MUI_COMPONENTSPAGE_TEXT_DESCRIPTION_TITLE "blablah 4"
!define MUI_COMPONENTSPAGE_TEXT_DESCRIPTION_INFO "blablah 5"
!define MUI_PAGE_CUSTOMFUNCTION_PRE prereqcreate
!define MUI_PAGE_CUSTOMFUNCTION_SHOW prereqshow
!insertmacro MUI_PAGE_COMPONENTS
!define MUI_PAGE_CUSTOMFUNCTION_PRE componentscreate
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Function .onInit
InitPluginsDir
StrCpy $0 0
loop:
ClearErrors
SectionGetText $0 $1
IfErrors done
WriteIniStr "$Pluginsdir\sec.ini" S $0 $1 ;Save section names...
IntOp $0 $0 + 1
Goto loop
done:
FunctionEnd
!macro ShowSections initial flip
StrCpy $0 0
StrCpy $2 ${initial}
loop:
ClearErrors
SectionGetText $0 $1
IfErrors done
ReadIniStr $1 "$Pluginsdir\sec.ini" S $0
IntCmpU 0 $2 "" +2 +2
StrCpy $1 ""
SectionSetText $0 $1
IntOp $0 $0 + 1
IntCmpU $0 ${flip} "" +2 +2
IntOp $2 $2 !
Goto loop
done:
!macroend
!macro CreatePreReq text name
Section /o "${text}" ${name}
SectionIn RO
SectionEnd
!macroend
!insertmacro CreatePreReq "Windows Installer v4.5" SEC_PRMSI
!insertmacro CreatePreReq ".NET v666" SEC_PRDOTNET
Section "Program files" SEC_PROG
;...
SectionEnd
Section "Desktop shortcut" SEC_DESKLNK
;...
SectionEnd
!define FIRSTREALSECTION ${SEC_PROG}
Function prereqcreate
!insertmacro ShowSections 1 ${FIRSTREALSECTION}
FunctionEnd
Function prereqshow
FindWindow $0 "#32770" "" $HWNDPARENT
GetDlgItem $1 $0 0x3FD
ShowWindow $1 0
GetDlgItem $1 $0 0x3FE
ShowWindow $1 0
GetDlgItem $1 $0 0x3FF
ShowWindow $1 0 ;hide space texts
GetDlgItem $1 $0 0x408
!define TVM_SETIMAGELIST 0x1109
SendMessage $1 ${TVM_SETIMAGELIST} 2 0 ;Remove images (leaking the imagelist in the process, oh well)
System::Call '*(&i24)i.r2'
System::Call 'user32::GetWindowRect(ir1,ir2)'
System::Call 'user32::MapWindowPoints(i0,ir0,ir2,i2)'
System::Call '*$2(i,i.r0,i.r3,i.r4)'
System::Free $2
IntOp $4 $4 - $0
System::Call 'user32::SetWindowPos(ir1,i0,i0,ir0,ir3,ir4,i0)'
FunctionEnd
Function componentscreate
!insertmacro ShowSections 0 ${FIRSTREALSECTION}
FunctionEnd
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_PRMSI} "You need MSI in a NSIS installer? ;)"
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_PRDOTNET} "You need moar bloat!"
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_PROG} "Required program files..."
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_DESKLNK} "Stupid desktop shortcut"
!insertmacro MUI_FUNCTION_DESCRIPTION_END
Related
I use the MUI_PAGE_INSTFILES. And this page has normally a finish-button, but I have a custom page after it. But I want that you could still finish the installer before the custom page and the next page is only optional. I could also show more code if wished.
!include "MUI2.nsh"
!insertmacro MUI_PAGE_LICENSE $(license)
!insertmacro MUI_PAGE_INSTFILES
Page custom TestSettings
At the moment I have a previous-, next- and cancel-button at the instfile page. But I want a prev-, next- and finish-button.
NSIS was never designed to support this but with the ButtonEvent plug-in you can make it work. I'm just not sure if it makes sense because if the last page is important then some users might skip the page by accident because they are not paying attention.
!include MUI2.nsh
!insertmacro MUI_PAGE_LICENSE $(license)
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE InstFilesLeave
!insertmacro MUI_PAGE_INSTFILES
Page custom TestSettings
!insertmacro MUI_LANGUAGE English
!include WinMessages.nsh
!include nsDialogs.nsh
Function InstFilesLeave
GetDlgItem $0 $hWndParent 2
ShowWindow $0 0
System::Call 'USER32::GetWindowRect(pr0,#r1)' ; NSIS 3+
System::Call 'USER32::MapWindowPoints(p0,p $hWndParent, p $1, i 2)'
System::Call '*$1(i.r2,i.r3,i.r4,i.r5)'
IntOp $4 $4 - $2
IntOp $5 $5 - $3
!define IDC_MYFINISHBTN 1337
System::Call 'USER32::CreateWindowEx(i 0, t "BUTTON", t "&Finish", i ${DEFAULT_STYLES}|${WS_TABSTOP}, ir2, ir3, i r4, i r5, p $hWndParent, p ${IDC_MYFINISHBTN}, p 0, p 0)p.r1'
SendMessage $0 ${WM_GETFONT} "" "" $0
SendMessage $1 ${WM_SETFONT} $0 1
GetFunctionAddress $0 OnFinishButton
ButtonEvent::AddEventHandler ${IDC_MYFINISHBTN} $0
FunctionEnd
Var JustFinish
Function OnFinishButton
StrCpy $JustFinish 1
SendMessage $hWndParent ${WM_COMMAND} 1 ""
FunctionEnd
Function TestSettings
StrCmp $JustFinish "" +2
Return
GetDlgItem $0 $hWndParent ${IDC_MYFINISHBTN}
ShowWindow $0 0
GetDlgItem $0 $hWndParent 2
ShowWindow $0 1
!insertmacro MUI_HEADER_TEXT "Configure" "Blah blah blah"
nsDialogs::Create 1018
Pop $0
; ...
nsDialogs::Show
FunctionEnd
If your custom page just contains a couple of checkboxes then you can use the MUI Finish page with custom texts instead.
I'm trying to add text or add an extra dialog at the end of an NSIS installer. So, to clarify, when the install has completed successfully I want to show some information.
I've seen various examples that touch on it but none seem to actually present a solution.
Does anyone have any info that can help?
You are already using the MUI so you can just customize the finish page text to fit your needs:
!include MUI2.nsh
!insertmacro MUI_PAGE_INSTFILES
!define MUI_FINISHPAGE_TITLE "Custom title"
!define MUI_FINISHPAGE_TITLE_3LINES
!define MUI_FINISHPAGE_TEXT "Custom text blah blah blah$\r$\nblah blah blah$\r$\nblah blah blah$\r$\nblah blah blah$\r$\nblah blah blah$\r$\n"
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_LANGUAGE English
And if that is unacceptable for whatever reason, you can create a totally custom page:
!include MUI2.nsh
!insertmacro MUI_PAGE_INSTFILES
AutoCloseWindow True ; Automatically move on from the InstFiles page
Page Custom MyFinishPageCreate
!insertmacro MUI_LANGUAGE English
!include nsDialogs.nsh
Function MyFinishPageCreate
!ifdef MUI_SYSVERSION
!insertmacro MUI_HEADER_TEXT "Title" "Sub-title"
!endif
nsDialogs::Create 1018
Pop $0
${NSD_CreateLabel} 0 0 100% 12u "Blah blah blah"
Pop $0
${NSD_CreateLabel} 0 30u 100% -30u "More blah blah blah"
Pop $0
nsDialogs::Show
FunctionEnd
If you want to display text directly on the InstFiles page you have to create a label control manually:
!include LogicLib.nsh
!include nsDialogs.nsh
!include WinMessages.nsh
Page InstFiles "" InstFilesShow
Var MyText
Function InstFilesShow
; Cannot use CreateWindowEx in a Section, must do it in the show callback
FindWindow $1 "#32770" "" $HWNDPARENT # Finds the inner dialog
System::Call 'USER32::CreateWindowEx(i${__NSD_Label_EXSTYLE},t "${__NSD_Label_CLASS}",t "Text goes here",i${__NSD_Label_STYLE},i10,i100,i300,i200,p$1,p0,p0,p0)p.s'
Pop $MyText
ShowWindow $MyText 0
SendMessage $1 ${WM_GETFONT} 0 0 $2
SendMessage $MyText ${WM_SETFONT} $2 1
FunctionEnd
Section
${IfNot} ${Abort}
ShowWindow $MyText 1
${EndIf}
SectionEnd
What I basically want is TeamViewer-like first page for my NSIS installer with the following options:
3 radio buttons for: Run Only; Install for current user; Install for all users (requires restart with admin rights).
A label for license like in TeamViewer (i.e. no actual EULA page, only a link to it in the footer).
A button that can change text, i.e. Accept and Run or Accept and Install.
I cannot figure out how to do it easily in terms of UI and in terms of control flow.
Also I need the ability to restart the installer if user decides to install program for all users (i.e. I guess there should be a detectable command line switch, so that if present installer will automatically assume 3rd install type).
A screenshot of a sample UI as requested:
A sample NSIS template would be greatly appreciated.
Thanks.
...
RequestExecutionLevel user
!include LogicLib.nsh
!include nsDialogs.nsh
!include FileFunc.nsh
!include MUI2.nsh
Var mode
Var modeRadioRun
Var modeRadioInstCU
Var modeRadioInstLM
Function OnRadioChange
GetDlgItem $1 $hwndparent 1 ; Find Install/Next button
${NSD_GetState} $modeRadioRun $0
${If} $0 = ${BST_CHECKED}
${NSD_SetText} $1 "Accept && Run"
${Else}
${NSD_SetText} $1 "Accept && Install"
${EndIf}
FunctionEnd
Function ModePageCreate
!insertmacro MUI_HEADER_TEXT "Welcome to blah" "blah blah"
${GetParameters} $0
ClearErrors
${GetOptions} "$0" "/ELEVATEDINSTALL" $0
${IfNot} ${Errors}
UserInfo::GetAccountType
Pop $0
${If} $0 == "Admin"
StrCpy $mode 1
Abort ; Skip page and start installing
${Else}
MessageBox mb_iconstop "Admin rights required!"
${EndIf}
${EndIf}
nsDialogs::Create 1018
Pop $0
${NSD_CreateRadioButton} 30u 20u 50% 12u "Run"
Pop $modeRadioRun
${NSD_OnClick} $modeRadioRun OnRadioChange
${NSD_CreateRadioButton} 30u 40u 50% 12u "Install for current user"
Pop $modeRadioInstCU
${NSD_OnClick} $modeRadioInstCU OnRadioChange
${NSD_CreateRadioButton} 30u 60u 50% 12u "Install for all users"
Pop $modeRadioInstLM
${NSD_OnClick} $modeRadioInstLM OnRadioChange
${NSD_CreateLink} 20u -14u 50% 12u "License"
Pop $0
${NSD_OnClick} $0 ShowLicense
${NSD_Check} $modeRadioRun
call OnRadioChange ; Trigger button change
nsDialogs::Show
FunctionEnd
Function ModePageLeave
${NSD_GetState} $modeRadioRun $0
${NSD_GetState} $modeRadioInstCU $1
${If} $0 = ${BST_CHECKED}
InitPluginsDir
SetOutPath $pluginsdir
File "myapp.exe"
ExecWait '"$pluginsdir\myapp.exe"'
SetOutPath $temp ; Don't lock $pluginsdir
Quit
${ElseIf} $1 = ${BST_CHECKED}
StrCpy $mode 0
${Else}
StrCpy $mode 1
UserInfo::GetAccountType
Pop $0
${If} $0 != "Admin"
ExecShell "runas" '"$exepath"' "/ELEVATEDINSTALL"
Quit
${EndIf}
${EndIf}
FunctionEnd
Function ShowLicense
ExecShell "" "http://example.com/license"
FunctionEnd
Page Custom ModePageCreate ModePageLeave
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Section
${If} $mode > 0
SetShellVarContext all
StrCpy $InstDir "$ProgramFiles\MyApp"
${Else}
SetShellVarContext current
StrCpy $InstDir "$LocalAppData\Programs\MyApp"
${EndIf}
SetOutPath $InstDir
File myapp.exe
CreateShortcut "$SMPrograms\MyApp.lnk" "$InstDir\myapp.exe"
WriteUninstaller "$InstDir\Uninst.exe"
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\MyAppGuid" "UninstallString" '"$InstDir\Uninst.exe"'
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\MyAppGuid" "DisplayName" "MyApp blah blah"
SectionEnd
Section Uninstall
; Todo: Remove files and registry entries (You should write to a .ini in $InstDir so you know if it was a per user or machine install)
RMDir "$InstDir"
SectionEnd
You might want to edit the base UI to make the install button larger with Resource Hacker (on one of the files in NSIS\Contrib\UIs) and in the script use ChangeUI to apply.
I have an NSIS installer script with two SectionGroups. Each SectionGroup has two Sections, which are mutually exclusive.
I need to have the user able to uncheck the SectionGroup, which unchecks and disables ("grays-out") the Sections. Basically the user can choose to install one of the Sections, or none. On top of that, the second SectionGroup must be disabled if the first SectionGroup is unchecked.
I'm using this script as reference to control the mutually exclusive Sections: http://nsis.sourceforge.net/Mutually_Exclusive_Sections
Thanks in advance.
Your disable/gray requirement does not make sense. If you click the section group again to enable the "child sections", which of the two gets checked? And you would only be able to get out of the disabled state by clicking the group itself so I did not implement it.
In general, anything beyond simple radio button behavior gets complicated quickly. If you are using the 3.0 alpha version of NSIS then .onSelChange will actually tell you which item that changed which would make this less complicated...
Page Components "" SaveState
Page Instfiles
!include sections.nsh
!include logiclib.nsh
SectionGroup /e "Grp1" GRP_1
Section "A" SEC_A
SectionEnd
Section /o "B" SEC_B
SectionEnd
SectionGroupEnd
SectionGroup /e "Grp2" GRP_2
Section /o "C" SEC_C
SectionEnd
Section "D" SEC_D
SectionEnd
SectionGroupEnd
; Remove comments for a different behavior
Function SaveState
!macro SaveSel id var
SectionGetFlags ${id} ${var}
IntOp ${var} ${var} & ${SF_SELECTED}
!macroend
#SectionGetFlags ${GRP_1} $R0
!insertmacro SaveSel ${SEC_A} $R1
!insertmacro SaveSel ${SEC_B} $R2
#SectionGetFlags ${GRP_2} $R3
!insertmacro SaveSel ${SEC_C} $R4
!insertmacro SaveSel ${SEC_D} $R5
FunctionEnd
Function .onSelChange
!macro OneOfTwoItemsInAGroup gid gv i1 v1 i2 v2
#SectionGetFlags ${gid} $0
!insertmacro SaveSel ${i1} $1
!insertmacro SaveSel ${i2} $2
${If} $1 <> 0
${AndIf} $2 <> 0
StrCpy $1 ${i1}
${IfThen} ${v1} = 0 ${|} StrCpy $1 ${i2} ${|}
!insertmacro UnselectSection $1
/*${If} ${gv} = $0
!insertmacro UnselectSection ${gid}
${EndIf}*/
${EndIf}
!macroend
!insertmacro OneOfTwoItemsInAGroup ${GRP_1} $R0 ${SEC_A} $R1 ${SEC_B} $R2
!insertmacro OneOfTwoItemsInAGroup ${GRP_2} $R3 ${SEC_C} $R4 ${SEC_D} $R5
Call SaveState
FunctionEnd
Is it possible to add a window(a Label) to an existing MUI page; like the installer page, welcome page?
I would like to add a new label to the installer page. My code below adds a new Static window to the window but its never shown/sits above other windows. I know the window exists because I can see it using WinSpy++ but it sits behind another window. Also the new window has a funny style "Style: 50000000 (hidden, enabled)" whilst other normal static windows have the style "Style: 5000008C (visible, enabled)".
How can I get my label(Static Window) to show?
!include nsdialogs.nsh
!include MUI2.nsh
!define MUI_PAGE_CUSTOMFUNCTION_SHOW instshow
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
OutFile "test.exe"
Function instshow
FindWindow $0 "#32770" "" $HWNDPARENT
GetDlgItem $2 $0 1016
System::Call 'USER32::CreateWindowEx(i0,t "STATIC",t "Some option",i ${WS_CHILD}|${WS_VISIBLE},i100,i100,i100,i20,i$2,i666,i0,i0) $R2'
System::Call `user32::SetWindowPos(i $R2, i ${HWND_TOP}, i 0, i 0, i 0, i 0, i ${SWP_NOSIZE}|${SWP_NOMOVE})` # attempt to push new label to front
# Attempt to refresh new labels parent window
GetDlgItem $R0 $HWNDPARENT 1016
ShowWindow $R0 ${SW_HIDE}
ShowWindow $R0 ${SW_SHOW}
# Attempt to refresh new label
ShowWindow $R2 ${SW_HIDE}
ShowWindow $R2 ${SW_SHOW}
FunctionEnd
Section "Dummy"
SectionEnd
Ok heres how to do it. Thanks for the advice Anders
!include nsdialogs.nsh
!include MUI2.nsh
!define MUI_PAGE_CUSTOMFUNCTION_SHOW instshow
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
OutFile "test.exe"
Function instshow
FindWindow $0 "#32770" "" $HWNDPARENT
System::Call 'USER32::CreateWindowEx(i0,t "STATIC",t "Some text",i ${WS_CHILD}|${WS_VISIBLE},i100,i100,i100,i20,i $0,i222,i0,i0) $R2'
GetDlgItem $1 $0 1027
GetDlgItem $2 $0 222
SendMessage $1 ${WM_GETFONT} 0 0 $3
SendMessage $2 ${WM_SETFONT} $3 1
FunctionEnd
Section "Dummy"
SectionEnd