Create custom page with NSIS - installation

I'd like to create a custom page using nsis. Just text, at different heights and possibly some image. Something similar to what oracle does:
From the docs at "Custom Pages" this is the way a custom page should be created:
;--------------------------------
;Pages
Function CustomPageFunction
!insertmacro MUI_HEADER_TEXT "TITLE" "SUBTITLE"
FunctionEnd
!insertmacro MUI_PAGE_WELCOME
Page custom CustomPageFunction
I am looking for additional guidlines on how to create very basic custom installer pages, because unfortunately, no new page with "TITLE" and "SUBTITLE" is displayed after MUI_PAGE_WELCOME as if extra instructions need to be added. What am I missing?ΕΎ
UPDATE for setting image:
var Image
var ImageHandle
Function CustomPageFunction
; !insertmacro MUI_HEADER_TEXT "TITLE" "SUBTITLE"
nsDialogs::Create 1044
Pop $0
${NSD_CreateBitmap} 0 0 100% 100% ""
Pop $Image
${NSD_SetImage} $Image "C:\Users\User\Desktop\TrickyWays\test.png" $ImageHandle
${NSD_CreateLabel} 0 0 100% 40% "Hello, welcome to nsDialogs!"
Pop $0
nsDialogs::Show
${NSD_FreeImage} $ImageHandle
FunctionEnd

The documentation you linked to only talks about custom pages in relation to the MUI header text. There is a ... there in the function where you are supposed to put the actual custom page code. I will try to fix that part of the documentation.
A custom page requires a plug-in and the most popular one is probably nsDialogs. A custom page that does not call a plug-in is automatically skipped.
!include nsDialogs.nsh
!include mui2.nsh
Function myPageCreate
!insertmacro MUI_HEADER_TEXT "TITLE" "SUBTITLE"
nsDialogs::Create 1018
Pop $0
${If} $0 == error
Abort
${EndIf}
${NSD_CreateLabel} 0 0 100% 12u "Hello, welcome to nsDialogs!"
Pop $0
${NSD_CreateText} 0 13u 100% -13u "Type something here..."
Pop $0
nsDialogs::Show
FunctionEnd
!insertmacro MUI_PAGE_WELCOME
Page custom myPageCreate
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE English

Related

NSIS: How to get a finish- and a next-button?

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.

Adding text to the completed dialog of an NSIS installer

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

Add a window to an existing MUI Page

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

using nsis installer, adding custom radiobuttons, calling sections according to radiobutton chosen

I want that if none of the RadioButtons are selected , then ,when the Next button is pressed, then it should give an alert that PLEASE CHOSE ATLEAST ONE ITEM, and it should not go to the next Dialog.
Also, I want that if the user selects the option : UPDATE EXISTING SOFTWARE, then only some files are copied, and if the other radiobutton is selected , then all files are copied,
Is this possible using sections or functions have to be used? can i call a Section, like if RadioButton 1 is chosen, then SECTION CREATEALLFILES is called, else SECTION CREATEONLYTWOFILES is called?
According to me, i think i want the code to HOW TO HOLD THE ids of these two RadioButtons and use them accordingly , to call different sections or functions. What would be the code? Please help?
Also, after pressing NEXT on this page, the next dialog will come as in image below: i want to show a LABEL , whether DEMO is done, or UPDATE is running, for this i will add a Label using Resource Hacker, but how to display that Label and hide it according to user choice of RadioButton
You can select/unselect sections or just put the logic in a single section, this example does both:
!include nsDialogs.nsh
!include Sections.nsh
var InstallType
Section
#Install common files...
${If} $InstallType == DEMO
#Do demo specific stuff
${Else}
#Do update specific stuff
${EndIf}
SectionEnd
Section "" SEC_DEMO
#Install demo..
SectionEnd
Section "" SEC_UPDATE
#Do update..
SectionEnd
Page custom InstTypePageCreate InstTypePageLeave
Function InstTypePageCreate
nsDialogs::Create 1018
pop $0
${NSD_CreateRadioButton} 0 50u 100% 10u "Demo"
pop $1
${IfThen} $InstallType == DEMO ${|} ${NSD_Check} $1 ${|}
${NSD_CreateRadioButton} 0 70u 100% 10u "Update"
pop $2
${IfThen} $InstallType == UPDATE ${|} ${NSD_Check} $2 ${|}
nsDialogs::Show
FunctionEnd
Function InstTypePageLeave
${NSD_GetState} $1 $0
${If} $0 = ${BST_CHECKED}
StrCpy $InstallType DEMO
!insertmacro UnselectSection ${SEC_UPDATE}
!insertmacro SelectSection ${SEC_DEMO}
${Else}
${NSD_GetState} $2 $0
${If} $0 = ${BST_CHECKED}
StrCpy $InstallType UPDATE
!insertmacro UnselectSection ${SEC_DEMO}
!insertmacro SelectSection ${SEC_UPDATE}
${Else}
MessageBox MB_ICONSTOP "You must select something!"
Abort
${EndIf}
${EndIf}
FunctionEnd
To set the text on the next page, just use ${NSD_SetText} $hwndYourLabel "Text" and ShowWindow inside a if block that tests $InstallType (This code needs to be in the show function callback (MUI_PAGE_CUSTOMFUNCTION_SHOW) for that page)

How to show some text on mouse move in NSIS installer

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

Resources