I need to make an installer that will also act as a repair/uninstall program if the concerned software is already installed.
I managed to make a custom page that check if the program exists and display buttons depending on that (the registry key creation is only for testing purpose and should be included in installation process).
For example, an Install button appears if the program isn't installed.
Here is the code doing this :
Page Custom MyCustomPage
var button
var buttonRepair
var buttonUninstall
var dialog
Function MyCustomPage
ReadRegStr $R0 HKLM ${P_DIR_REGKEY} "Version"
${If} ${Errors}
Goto NotInstalled
${Else}
Goto Installed
${EndIf}
NotInstalled:
nsDialogs::Create 1018
;Pop $dialog
${NSD_CreateButton} 25% 25% 50% 50% "Install"
Pop $button
EnableWindow $button 1 # start out disabled
WriteRegStr HKLM ${P_DIR_REGKEY} "Version" ${P_VERSION}
WriteRegStr HKLM ${P_DIR_REGKEY} "" "$INSTDIR\asd.exe"
nsDialogs::Show
${NSD_OnClick} $button ManageInstall
Goto MyEnd
Installed:
nsDialogs::Create 1018
Pop $0
${NSD_CreateButton} 12% 12% 25% 25% "Repair"
Pop $buttonRepair
${NSD_CreateButton} 37% 12% 25% 25% "Uninstall"
Pop $buttonUninstall
EnableWindow $button 1 # start out disabled
EnableWindow $button2 1
${NSD_OnClick} $buttonRepair ManageRepair
${NSD_OnClick} $buttonUninstall ManageUninstall
nsDialogs::Show
Goto MyEnd
MyEnd:
Quit
FunctionEnd
Function ManageInstall
MessageBox MB_OK "Installation"
FunctionEnd
Function ManageRepair
MessageBox MB_OK "Repair"
FunctionEnd
Function ManageUninstall
MessageBox MB_OK "Uninstallation"
FunctionEnd
The problem is that it's all managed by functions, and I can't declare new pages macros in them, so I can't continue with the proper installation through sections because of it.
How should I manage the different actions to be taken by the installer to be able to make user friendly pages like a normal install ?
Should I use custom pages for every single action, because it sounds a bit fastidious and complicated ?
I recommend you create a variable named "ACTION", and set its value when the user clicks an option. And then, jump to the next page. Something like this:
# http://nsis.sourceforge.net/Go_to_a_NSIS_page
Function RelGotoPage
IntCmp $R9 0 0 Move Move
StrCmp $R9 "X" 0 Move
StrCpy $R9 "120"
Move:
SendMessage $HWNDPARENT "0x408" "$R9" ""
FunctionEnd
Function GotoNextPage
StrCpy $R9 "1"
Call RelGotoPage
FunctionEnd
Function ManageRepair
StrCpy $ACTION "repair"
Call GotoNextPage
Abort
FunctionEnd
Then, on each page's "pre" function, you need to check it it has to be displayed or not:
Function repairpage
# Do not display this page unless user selected Repair.
${if} "$ACTION" != "repair"
Abort
$[EndIf}
....
FunctionEnd
Related
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
So what you gave me works great.
Now the question is how do I set it so the password page has a message on it asking for you to inter your password This is what I have so far.
Function leave
${NSD_GetText} $hwnd $0
${If} $0 != "web9^root"
MessageBox MB_OK "Please enter a valid security code"
Abort
${EndIf}
FunctionEnd
Function pre
nsDialogs::Create 1018
Pop $dialog
${NSD_CreatePassword} 0 0 50% 8% ""
Pop $hwnd
nsDialogs::show
FunctionEnd
======================
so i have the following script set up to run,
!include "nsDialogs.nsh"
!include "winmessages.nsh"
!include "logiclib.nsh"
OutFile "test.exe"
Page Custom pre
var dialog
var hwnd
Function pre
nsDialogs::Create 1018
Pop $dialog
${NSD_CreatePassword} 0 0 50% 8% "web9^root"
Pop $hwnd
SendMessage $hwnd ${EM_SETPASSWORDCHAR} 149 0 # 149 = medium dot
nsDialogs::Show
FunctionEnd
Section ""
SectionEnd
How do I make it so that if you do not know the password it will not let you pass. I also need to know who to set it so that the password is not already in the text feild. Can you all help me with this
you will have to add a leave function for that nsdialogs page...
Page custom pre leave
...and there you verify the password...
Function leave
${NSD_GetText} $hwnd $0
${If} $0 != "yourPassword"
MessageBox MB_OK "Wrong password"
Abort
${EndIf}
FunctionEnd
if you don't want the password in that field, just leave it empty when creating the dialog!
I have created EXE file using NSIS script.I have created custom page using following code,
page custom check
Function check
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 $Dialog12
${If} $Dialog12 == error
Abort
${EndIf}
${NSD_CreateRadioButton} 0 5u 100% 10u "Repair"
Pop $Repair
${NSD_CreateRadioButton} 0 25u 100% 56u "Remove"
Pop $Remove
${NSD_SetState} $Repair ${BST_CHECKED}
${NSD_GetState} $Repair $test
--Do repair operation--
${NSD_OnClick} $Remove "Remove"
nsDialogs::Show
${NSD_GetState} $Remove $RadioButton_State
${If} $RadioButton_State == ${BST_CHECKED}
call Removed
${Else}
Goto Done
${EndIf}
Done:
FunctionEnd
Function Remove
nsDialogs::Create 1018
Pop $Dialog12
${If} $Dialog12 == error
Abort
${EndIf}
--Do remove function--
/* nsDialogs::Show*/
FunctionEnd
If I run the above code it's not working.No code executed after show function.If i give show function before functionEnd it throws me Run time exception.Because inside Remove function also have one more show().
My Requirement is,
If the user clicks the remove radio button,moves to next page and do the un install process and page comes to end.I have tried this scenario using above code.but its working fine.
How to include two custom pages in nsis installer?
Can anyone help me?
Thanks.
You can add two custom pages in just the same way you are adding a custom page:
Page custom check
Page custom Remove
As Anders said, everything you put after nsDialogs::Show doesn't get executed. You need to move this code to a new "leave" function:
Var RemoveRequested
Function RemoveCheck
${NSD_GetState} $Remove $RadioButton_State
${If} $RadioButton_State == ${BST_CHECKED}
StrCpy $RemoveRequested "1"
${Else}
StrCpy $RemoveRequested "0"
${EndIf}
FunctioEnd
You are saving the user selection in a global variable $RemoveRequested. Then, in the next custom page you can check this variable, and do anything you need, or just Abort and the second page will not be displayed.
And then, you need to modify your custom pages declaration:
Page custom check RemoveCheck
Page custom Remove
Now, check will be used to show the custom page, and when the user leaves the page (== clicks on "Next"), the function RemoveCheck will be executed.
Your Remove function should check the flag we just created:
Function Remove
${If} $RemoveRequested == "1"
nsDialogs::Create 1018
Pop $Dialog12
${If} $Dialog12 == error
Abort
${EndIf}
--Do remove function--
/* nsDialogs::Show*/
${EndIf}
FunctionEnd
After nsDialogs::Show the page is basically gone, do your work in the leave callback: Page custom nsDialogpage dotheradiocheckinthisfunction
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
I have created customize page with two radio button for repair and remove.If the user select the repair button it goes for repair fun.but again come to old page that is repair and remove page.so the user selects both option.My requirement is user selects only one option and do corresponding actions only.No need to give the option to select both the buttons.
Function nsDialogpage
nsDialogs::Create 1018
Pop $Dialog
${If} $Dialog == error
Abort
${EndIf}
${NSD_CreateRadioButton} 0 5u 100% 10u "Repair"
Pop $Repair
${NSD_AddStyle} $Repair ${WS_GROUP}
${NSD_OnClick} $Repair Repair
${NSD_CreateRadioButton} 0 25u 100% 56u "Remove"
Pop $Remove
${NSD_OnClick} $Remove Remove
nsDialogs::Show
FunctionEnd
Function Repair
-- Do repair function.
FunctionEnd
Function Remove
ExecWait "$INSTDIR\uninstall.exe"
Quit
FunctionEnd
also if remove fun have remove the installer and quit the installation.
uninstaller has been done successfully.but installer again go main page after that user click any button then only quit from installation steps.
1.User select any one option and leave this repair and remove page.
2.If user click remove option remove the installer and immediately quit the process.
Quit does not quit right away when used in a page action callback, it will quit when the page changes. Performing some action when a radio button is clicked is not normal Windows behavior (Try pressing TAB) so I added a normal example aswell.
!include nsDialogs.nsh
Page Custom RepairOrRemovePageInsane_Create
Page Custom RepairOrRemovePageNormal_Create RepairOrRemovePageNormal_Leave
Page InstFiles
Function Remove
ExecWait '"cmd" /C echo This is a dummy uninstall command...&pause' ; Call real uninstaller here
FunctionEnd
Function Repair
# Do repair....
FunctionEnd
Function RepairOrRemovePageInsane_Create
nsDialogs::Create 1018
Pop $0
${NSD_CreateRadioButton} 0 5u 100% 10u "Repair"
Pop $0
SendMessage $HWNDPARENT ${WM_NEXTDLGCTL} $0 1
${NSD_OnClick} $0 RepairInsane
${NSD_CreateRadioButton} 0 25u 100% 56u "Remove"
Pop $0
${NSD_OnClick} $0 RemoveInsane
GetDlgItem $0 $hwndparent 1 ; Get Next button handle and
EnableWindow $0 0 ; ...disable it because it does not make sense with this insane radio button handling
nsDialogs::Show
FunctionEnd
Function RemoveInsane
Call Remove
SendMessage $HWNDPARENT ${WM_CLOSE} 0 0
FunctionEnd
Function RepairInsane
Call Repair
SendMessage $HWNDPARENT 0x408 1 0 ; Go to next page
FunctionEnd
Function RepairOrRemovePageNormal_Create
nsDialogs::Create 1018
Pop $1
${NSD_CreateRadioButton} 0 5u 100% 10u "Repair"
Pop $1
${NSD_CreateRadioButton} 0 25u 100% 56u "Remove"
Pop $2
SendMessage $1 ${BM_CLICK} 0 0 ; Select one of them by default
nsDialogs::Show
FunctionEnd
Function RepairOrRemovePageNormal_Leave
${NSD_GetState} $1 $0
${If} $0 <> 0
Call Repair
${Else}
Call Remove
Quit
${EndIf}
FunctionEnd