NSIS Resetting text and droplists upon button press - nsis

Hope you guys can help me out again. I have created a custom page, and in that page are sever text fieldsa and 2 droplists. I also have a clear button that if pressed it clears all the fields on the screen.
Note: I used the code from TestNotify.nsu in examples
The issue I have is one, when pressing clear the values are written to the ini file so upon reloading the program the last Fields used populate (Even if I press clear, I have to press it twice clear the ini file)
Second is how do I reset the droplist to the default I selected when pressing reset.
So the only section I am working on now is the clearbtn, so how can i reset the droplists to a specific value, and clear data from ini when pressing clear only once.
###Add Auto Start option
SetCompressor lzma
XPStyle on
!define FolderImages "Included\Images"
!define ImageIcon "Icon.ico"
!define ImageHDR "HDR.bmp"
!define PRODUCT_NAME "Test"
!define PRODUCT_VERSION "1.0"
!define MUI_ICON ".\${FolderImages}\${ImageIcon}"
Icon ".\${FolderImages}\${ImageIcon}"
!include WinVer.nsh
!include LogicLib.nsh
!include x64.nsh
!include FileFunc.nsh
!include MUI.nsh
!include WinMessages.nsh
!include InstallOptions.nsh
!include Sections.nsh
!include nsDialogs.nsh
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP ".\${FolderImages}\${ImageHDR}"
Page custom SetCustom ValidateCustom
!insertmacro MUI_LANGUAGE "English"
Function SetCustom
!insertmacro MUI_HEADER_TEXT "Licence Key Generator" "Create or Read Licence Keys"
#Hides the close button
GetDlgItem $R0 $HWNDPARENT 1
ShowWindow $R0 ${SW_HIDE}
InstallOptions::initDialog ".\UserProfiles.ini"
; In this mode InstallOptions returns the window handle so we can use it
Pop $0
; Now show the dialog and wait for it to finish
InstallOptions::show
; Finally fetch the InstallOptions status value (we don't care what it is though)
Pop $0
FunctionEnd
Function ValidateCustom
# At this point the user has either pressed cancel or one of our custom buttons
# We find out which by reading from the INI file
ReadINIStr $0 ".\UserProfiles.ini" "Settings" "State"
StrCmp $0 0 cancelbtn
StrCmp $0 19 createbtn
StrCmp $0 20 readbtn
StrCmp $0 21 comparebtn
StrCmp $0 22 clearbtn
Abort # Return to the page
createbtn:
Abort # Return to the page
readbtn:
Abort # Return to the page
comparebtn:
Abort # Return to the page
clearbtn:
#Text Field
ReadINIStr $1 ".\UserProfiles.ini" "Field 6" "HWND"
SendMessage $1 ${WM_SETTEXT} 0 "STR:"
#Text Field
ReadINIStr $1 ".\UserProfiles.ini" "Field 8" "HWND"
SendMessage $1 ${WM_SETTEXT} 0 "STR:"
#Text Field
ReadINIStr $1 ".\UserProfiles.ini" "Field 10" "HWND"
SendMessage $1 ${WM_SETTEXT} 0 "STR:"
#Drop List ------------------------------------------------------------<<<<
ReadINIStr $1 ".\UserProfiles.ini" "Field 12" "HWND"
SendMessage $1 ${WM_SETTETX} 0 "STR:"
#Text Field
ReadINIStr $1 ".\UserProfiles.ini" "Field 14" "HWND"
SendMessage $1 ${WM_SETTEXT} 0 "STR:"
#Drop List ------------------------------------------------------------<<<<
ReadINIStr $1 ".\UserProfiles.ini" "Field 16" "HWND"
SendMessage $1 ${WM_SETTEXT} 0 "STR:"
#Text Field
ReadINIStr $1 ".\UserProfiles.ini" "Field 18" "HWND"
SendMessage $1 ${WM_SETTEXT} 0 "STR:"
Abort # Return to the page
cancelbtn:
FunctionEnd
Section Dummy
SectionEnd

You can clear a droplist by sending the CB_RESETCONTENT message:
Var MyDir
Function .onInit
; Create example .ini
InitPluginsDir
StrCpy $MyDir $Temp ; Use something else in a real application, or use $PluginsDir.
WriteIniStr "$MyDir\UserProfiles.ini" "Settings" NumFields 4
WriteIniStr "$MyDir\UserProfiles.ini" "Field 1" Type Button
WriteIniStr "$MyDir\UserProfiles.ini" "Field 1" Left 0
WriteIniStr "$MyDir\UserProfiles.ini" "Field 1" Right 50
WriteIniStr "$MyDir\UserProfiles.ini" "Field 1" Top 0
WriteIniStr "$MyDir\UserProfiles.ini" "Field 1" Bottom 14
WriteIniStr "$MyDir\UserProfiles.ini" "Field 1" Text "&Clear"
WriteIniStr "$MyDir\UserProfiles.ini" "Field 1" Flags NOTIFY
WriteIniStr "$MyDir\UserProfiles.ini" "Field 2" Type Text
WriteIniStr "$MyDir\UserProfiles.ini" "Field 2" Left 0
WriteIniStr "$MyDir\UserProfiles.ini" "Field 2" Right 100
WriteIniStr "$MyDir\UserProfiles.ini" "Field 2" Top 15
WriteIniStr "$MyDir\UserProfiles.ini" "Field 2" Bottom 30
WriteIniStr "$MyDir\UserProfiles.ini" "Field 3" Type Droplist
WriteIniStr "$MyDir\UserProfiles.ini" "Field 3" Left 0
WriteIniStr "$MyDir\UserProfiles.ini" "Field 3" Right 100
WriteIniStr "$MyDir\UserProfiles.ini" "Field 3" Top 35
WriteIniStr "$MyDir\UserProfiles.ini" "Field 3" Bottom 99
WriteIniStr "$MyDir\UserProfiles.ini" "Field 4" Type Button
WriteIniStr "$MyDir\UserProfiles.ini" "Field 4" Left 55
WriteIniStr "$MyDir\UserProfiles.ini" "Field 4" Right 105
WriteIniStr "$MyDir\UserProfiles.ini" "Field 4" Top 0
WriteIniStr "$MyDir\UserProfiles.ini" "Field 4" Bottom 14
WriteIniStr "$MyDir\UserProfiles.ini" "Field 4" Text "&Add"
WriteIniStr "$MyDir\UserProfiles.ini" "Field 4" Flags NOTIFY
FunctionEnd
Function SetCustom
InstallOptions::initDialog "$MyDir\UserProfiles.ini"
; In this mode InstallOptions returns the window handle so we can use it
Pop $0
; Now show the dialog and wait for it to finish
InstallOptions::show
; Finally fetch the InstallOptions status value (we don't care what it is though)
Pop $0
FunctionEnd
Function ValidateCustom
# At this point the user has either pressed cancel or one of our custom buttons
# We find out which by reading from the INI file
ReadINIStr $0 "$MyDir\UserProfiles.ini" "Settings" "State"
StrCmp $0 1 clearbtn
StrCmp $0 4 addbtn
Abort # Return to the page
clearbtn:
#Text Field
ReadINIStr $1 "$MyDir\UserProfiles.ini" "Field 2" "HWND"
SendMessage $1 ${WM_SETTEXT} 0 "STR:"
#Droplist Field
ReadINIStr $2 "$MyDir\UserProfiles.ini" "Field 3" "HWND"
SendMessage $2 ${CB_RESETCONTENT} 0 0
DeleteIniStr "$MyDir\UserProfiles.ini" "Field 3" "ListItems"
DeleteIniStr "$MyDir\UserProfiles.ini" "Field 3" "State"
Abort # Return to the page
addbtn:
ReadINIStr $1 "$MyDir\UserProfiles.ini" "Field 2" "State"
ReadINIStr $2 "$MyDir\UserProfiles.ini" "Field 3" "HWND"
SendMessage $2 ${CB_ADDSTRING} 0 "STR:$1"
SendMessage $2 ${CB_SELECTSTRING} 0 "STR:$1"
Abort # Return to the page
FunctionEnd
You should not use relative .INI paths, that is just asking for trouble, use full paths!

Related

How use to NSIS textbox, button event?

I want to pass external .exe parameters via IP textbox and Key textbox.
This is my Setup code. The external .exe receives three parameters.
The first is the product name, the second is the ip, the third is the key.
You do not know how to write nsis to pass external parameters.
How to use is confusing.
Under Code(Setup.nsi)
## input lincesekey, ip
Function PageInputLicenseInfo
ReserveFile "pageInputLicenseInfo.ini"
!insertmacro MUI_INSTALLOPTIONS_EXTRACT "pageInputLicenseInfo.ini"
!insertmacro MUI_INSTALLOPTIONS_DISPLAY "pageInputLicenseInfo.ini"
FunctionEnd
## I want to pass external .exe parameters
Function MyCustomLicense
#IP
!insertmacro MUI_INSTALLOPTIONS_READ $R0 "pageInputLicenseInfo.ini" "Field 3" "State"
${If} $R0 == "1"
Exec '"$INSTDIR\JCertFileGenerator.exe "/${PRODUCT_NAME},$R0""'
${EndIf}
#KEY
!insertmacro MUI_INSTALLOPTIONS_READ $R1 "pageInputLicenseInfo.ini" "Field 4" "State"
${If} $R1 == "1"
Exec '"$INSTDIR\JCertFileGenerator.exe "/${PRODUCT_NAME},$R0,$R1""'
${EndIf}
## external .exe
!insertmacro MUI_INSTALLOPTIONS_READ $R2 "pageInputLicenseInfo.ini" "Field 5" "State"
${If} $R2 == "1"
File "..\ADAgent\bin\Release\JCertFileGenerator.exe"
Exec '"$INSTDIR\JCertFileGenerator.exe "/${PRODUCT_NAME},$R0,$R1""'
${EndIf}
FunctionEnd
Under Code(pageInputLicenseInfo.ini)
Ini file generated by the HM NIS Edit IO designer.
[Settings]
NumFields=5
[Field 1]
Type=Label
Text=IP
Left=6
Right=37
Top=8
Bottom=19
[Field 2]
Type=Label
Text=License Key
Left=5
Right=64
Top=24
Bottom=35
[Field 3]
Type=Text
Left=65
Right=274
Top=4
Bottom=16
State=1
[Field 4]
Type=Text
Left=65
Right=274
Top=20
Bottom=33
State=1
[Field 5]
Type=Button
Text=확인
Flags=NOTIFY
Left=225
Right=275
Top=40
Bottom=56
State=1
I would appreciate if you write a method for passing parameters to an external .exe using fields 3,4,5.
Your command-line quotes are wrong and you also fail to extract JCertFileGenerator.exe in some of the code-paths!
Quoting should look like this:
Exec '"c:\my path\program.exe" param1 "param with spaces" /param3'
And here is a silly example:
Unicode True
!define PRODUCT_NAME "Hello World"
Name "${PRODUCT_NAME}"
OutFile Test.exe
!include MUI.nsh
!include LogicLib.nsh
!include InstallOptions.nsh
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
Page Custom LicensekeyPageCreate LicensekeyPageNotify
!insertmacro MUI_LANGUAGE English
Function .onInit
; I'm writing the .ini directly here because this is just an example
InitPluginsDir
FileOpen $0 "$PluginsDir\pageInputLicenseInfo.ini" a
FileWriteUTF16LE /BOM $0 ""
FileClose $0
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Settings" NumFields 5
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 1" Type Label
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 1" Text IP
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 1" Left 6
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 1" Right 37
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 1" Top 8
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 1" Bottom 19
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 2" Type Label
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 2" Text "License Key"
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 2" Left 5
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 2" Right 64
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 2" Top 24
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 2" Bottom 35
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 3" Type Text
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 3" Left 65
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 3" Right 274
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 3" Top 4
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 3" Bottom 16
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 3" State 1
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 4" Type Text
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 4" Left 65
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 4" Right 274
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 4" Top 20
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 4" Bottom 33
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 4" State 1
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 5" Type Button
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 5" Text "${U+d655}${U+c778}"
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 5" Flags NOTIFY
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 5" Left 225
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 5" Right 275
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 5" Top 40
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 5" Bottom 56
WriteIniStr "$PluginsDir\pageInputLicenseInfo.ini" "Field 5" State 1
FunctionEnd
Function LicenseKeyPageCreate
!insertmacro INSTALLOPTIONS_DISPLAY "pageInputLicenseInfo.ini"
FunctionEnd
Function LicensekeyPageNotify
!insertmacro INSTALLOPTIONS_READ $0 "pageInputLicenseInfo.ini" "Settings" "State"
${If} $0 = 5 ; Was the button clicked?
!insertmacro MUI_INSTALLOPTIONS_READ $R0 "pageInputLicenseInfo.ini" "Field 3" "State"
!insertmacro MUI_INSTALLOPTIONS_READ $R1 "pageInputLicenseInfo.ini" "Field 4" "State"
ExecWait '"cmd.exe" /C echo "${PRODUCT_NAME}" IP=$R0 Key="$R1" &pause'
Abort ; Stay on the current page
${EndIf}
FunctionEnd
Executing something in $InstDir before you get to the InstFiles page is usually not a good idea, you might want to use $PluginsDir instead or ask for the license key information after the InstFiles page.

Increase buffer size for "Writeinistr" in nsis

I am new for nsis
Created ini page which contains "Text" type, using this type i was showing the some dynamic data in the label. The size of file is 2 kb, so i need to increase the size for "State" option in "Text" type. So how to increase the size of State using writeinistr?
To bypass the NSIS string length limitation you have to call the Windows API directly:
Page Custom MyPage
Page InstFiles
!macro IniWriteAsciiStringPtr ini sec name strptr
!if "${NSIS_CHAR_SIZE}" > 1
Push $0
Push $1
Push $2
Push "${ini}"
Push "${name}"
Push "${sec}"
StrCpy $0 ${strptr}
System::Call 'kernel32::MultiByteToWideChar(i0, i0, i$0, i-1, i0, i0)i.r2'
System::Call '*(&w$2)i.r1'
System::Call 'kernel32::MultiByteToWideChar(i0, i0, i$0, i-1, ir1, ir2)'
System::Call 'kernel32::WritePrivateProfileString(t s, t s, ir1, t s)'
System::Free $1
Pop $2
Pop $1
Pop $0
!else
System::Call 'kernel32::WritePrivateProfileString(t "${sec}", t "${name}", i ${strptr}, t "${ini}")'
!endif
!macroend
!include InstallOptions.nsh
Function MyPage
InitPluginsDir
; Building the entire .ini at run-time in this example
WriteIniStr "$PluginsDir\io.ini" Settings NumFields 1
WriteIniStr "$PluginsDir\io.ini" "Field 1" Type Text
WriteIniStr "$PluginsDir\io.ini" "Field 1" Left 1
WriteIniStr "$PluginsDir\io.ini" "Field 1" Right -2
WriteIniStr "$PluginsDir\io.ini" "Field 1" Top 5
WriteIniStr "$PluginsDir\io.ini" "Field 1" Bottom -10
WriteIniStr "$PluginsDir\io.ini" "Field 1" Flags MULTILINE
FileOpen $0 "$PluginsDir\test.txt" r
FileSeek $0 0 END $1
FileSeek $0 0 SET
System::Call '*(&i$1,i0)i.r2'
System::Call 'kernel32::ReadFile(ir0,ir2,ir1,*i,i0)'
!insertmacro IniWriteAsciiStringPtr "$PluginsDir\io.ini" "Field 1" "State" $2
System::Free $2
FileClose $0
!insertmacro INSTALLOPTIONS_DISPLAY "io.ini"
FunctionEnd
Function .onInit
InitPluginsDir
; Create a big file for this example
FileOpen $0 "$PluginsDir\test.txt" w
StrCpy $2 0
loop:
StrCmp $2 2048 done
IntOp $1 $2 % 10
StrCmp $2 2047 0 +2
StrCpy $1 "!"
FileWrite $0 $1
IntOp $2 $2 + 1
Goto loop
done:
FileClose $0
FunctionEnd
You can also bypass the .ini and set it directly in the dialog:
Page Custom MyPage
Page InstFiles
!include InstallOptions.nsh
!include WinMessages.nsh
Function MyPage
InitPluginsDir
; Building the entire .ini at run-time in this example
WriteIniStr "$PluginsDir\io.ini" Settings NumFields 1
WriteIniStr "$PluginsDir\io.ini" "Field 1" Type Text
WriteIniStr "$PluginsDir\io.ini" "Field 1" Left 1
WriteIniStr "$PluginsDir\io.ini" "Field 1" Right -2
WriteIniStr "$PluginsDir\io.ini" "Field 1" Top 5
WriteIniStr "$PluginsDir\io.ini" "Field 1" Bottom -10
WriteIniStr "$PluginsDir\io.ini" "Field 1" Flags MULTILINE
FileOpen $0 "$PluginsDir\test.txt" r
FileSeek $0 0 END $1
FileSeek $0 0 SET
System::Call '*(&i$1,i0)i.r2'
System::Call 'kernel32::ReadFile(ir0,ir2,ir1,*i,i0)'
FileClose $0
!insertmacro INSTALLOPTIONS_INITDIALOG "io.ini"
Pop $0
!insertmacro INSTALLOPTIONS_READ $0 "io.ini" "Field 1" "HWND"
!if "${NSIS_CHAR_SIZE}" > 1
!error TODO
!else
SendMessage $0 ${WM_SETTEXT} 0 $2
!endif
System::Free $2
!insertmacro INSTALLOPTIONS_SHOW
FunctionEnd
Function .onInit
InitPluginsDir
; Create a big file for this example
FileOpen $0 "$PluginsDir\test.txt" w
StrCpy $2 0
loop:
StrCmp $2 2048 done
IntOp $1 $2 % 10
StrCmp $2 2047 0 +2
StrCpy $1 "!"
FileWrite $0 $1
IntOp $2 $2 + 1
Goto loop
done:
FileClose $0
FunctionEnd

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

NSIS script + Skip button alignment issue

I am trying NSIS script to add "SKIP" button.
I have tested below code and it works well but when I actually integrate with the main code which is having a screen of option "back" "Next" and "Cancel" button. this skip button is not visible at all, it is in extreme right of cancel button and hardly visible.
How can move this "Skip" button towards left side.
Name BtnTest
Outfile test.exe
Installdir "$temp"
RequestExecutionLevel user
BrandingText " " ;Button covers this text
!include nsDialogs.nsh ;For WS_*
!define MUI_CUSTOMFUNCTION_GUIINIT SKIP
Function SKIP
; You are supposed to use ChangeUI (or MUI_UI) and a modified ui file to add new buttons but this example adds the button at run-time...
GetDlgItem $0 $hwndparent 2 ; Find cancel button
System::Call *(i,i,i,i)i.r1
System::Call 'USER32::GetWindowRect(ir0,ir1)'
System::Call *$1(i.r2,i.r3,i.r4,i.r5)
IntOp $5 $5 - $3 ;height
IntOp $4 $4 - $2 ;width
System::Call 'USER32::ScreenToClient(i$hwndparent,ir1)'
System::Call *$1(i.r2,i.r3)
System::Free $1
IntOp $2 $2 + $4 ;x
IntOp $2 $2 + 8 ;x+padding
System::Call 'USER32::CreateWindowEx(i0,t "Button",t "Click Me",i${WS_CHILD}|${WS_VISIBLE}|${WS_TABSTOP},ir2,ir3,ir4,ir5,i $hwndparent,i 0x666,i0,i0)i.r0'
SendMessage $hwndparent ${WM_GETFONT} 0 0 $1
SendMessage $0 ${WM_SETFONT} $1 1
GetFunctionAddress $0 onmybtnclick
ButtonEvent::AddEventHandler 0x666 $0
FunctionEnd
Function onmybtnclick
MessageBox mb_ok "You clicked me!"
FunctionEnd
Page Directory
Page Instfiles
Section
SectionEnd
And also this button appears on all screen How can I display only in one screen.
Change $2 and $3 before the call to CreateWindowEx to change the button position. You can save the handle to the button in another variable after CreateWindowEx but I just used the Id in this example (0x666).
Name BtnTest
Outfile test.exe
Installdir "$temp"
RequestExecutionLevel user
BrandingText " " ;Button covers this text
!include nsDialogs.nsh ;For WS_*
!define MUI_CUSTOMFUNCTION_GUIINIT SKIP
/**/ !include MUI2.nsh #*/
!ifndef MUI_INCLUDED
Function .onGuiInit
Call SKIP
FunctionEnd
!endif
Function SKIP
; You are supposed to use ChangeUI (or MUI_UI) and a modified ui file to add new buttons but this example adds the button at run-time...
GetDlgItem $0 $hwndparent 2 ; Find cancel button
System::Call *(i,i,i,i)i.r1
System::Call 'USER32::GetWindowRect(ir0,ir1)'
System::Call *$1(i.r2,i.r3,i.r4,i.r5)
IntOp $5 $5 - $3 ;height
IntOp $4 $4 - $2 ;width
System::Call 'USER32::ScreenToClient(i$hwndparent,ir1)'
System::Call *$1(i.r2,i.r3)
System::Free $1
!ifdef MUI_INCLUDED
StrCpy $2 15 ; Whatever you feel looks good
!else
IntOp $2 $2 + $4 ;x
IntOp $2 $2 + 8 ;x+padding
!endif
System::Call 'USER32::CreateWindowEx(i0,t "Button",t "Click Me",i${WS_CHILD}|${WS_VISIBLE}|${WS_TABSTOP},ir2,ir3,ir4,ir5,i $hwndparent,i 0x666,i0,i0)i.r0'
SendMessage $hwndparent ${WM_GETFONT} 0 0 $1
SendMessage $0 ${WM_SETFONT} $1 1
GetFunctionAddress $0 onmybtnclick
ButtonEvent::AddEventHandler 0x666 $0
FunctionEnd
Function onmybtnclick
MessageBox mb_ok "You clicked me!"
FunctionEnd
Function HideIt
GetDlgItem $0 $hwndparent 0x666
ShowWindow $0 0
FunctionEnd
Function ShowIt
GetDlgItem $0 $hwndparent 0x666
ShowWindow $0 1
FunctionEnd
!ifdef MUI_INCLUDED
!define MUI_PAGE_CUSTOMFUNCTION_SHOW HideIt
!insertmacro MUI_PAGE_COMPONENTS
!define MUI_PAGE_CUSTOMFUNCTION_SHOW ShowIt
!insertmacro MUI_PAGE_COMPONENTS
!define MUI_PAGE_CUSTOMFUNCTION_SHOW HideIt
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE English
!else
Page Components "" HideIt
Page Components "" ShowIt
Page Components "" HideIt
Page Instfiles
!endif
Section
SectionEnd

NSIS - Custom Page, problems with a droplist

I have this Custom Page in my code, where there is a droplist with the available drives on the computer. When the user chooses the drive he wants, a .txt file is created where is written that drive (example: E:).
When you open the custom page, the drive that appear on the droplist is "C:\". But if I hit "next" without clicking on the droplist, the .txt file is not created. Even if I want C:\ and it's already there, I have to go there and click to make it work. If I don't click on the droplist before hiting "next", nothing happen.
Anybody knows why? The code is down below:
!include "MUI2.nsh"
!include FileFunc.nsh
!insertmacro GetDrives
var newCheckBox
!define NOME "S-Monitor"
Name "${NOME}"
OutFile "${NOME}.exe"
InstallDir "C:\${NOME}"
ShowInstDetails show
AllowRootDirInstall true
;--- Paginas ---
!define MUI_ICON Labels\SetupICO.ico
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_RIGHT
!define MUI_HEADERIMAGE_BITMAP Labels\Header.bmp
!define MUI_WELCOMEFINISHPAGE_BITMAP Labels\Left.bmp
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
Page Custom CustomCreate CustomLeave
!define MUI_FINISHPAGE_NOAUTOCLOSE
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_CHECKED
!define MUI_FINISHPAGE_RUN_TEXT "Criar atalho na Área de Trabalho"
!define MUI_FINISHPAGE_RUN_FUNCTION "AtalhoDesktop"
!define MUI_PAGE_CUSTOMFUNCTION_SHOW showNewCheckbox
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE launchNewLink
!insertmacro MUI_PAGE_FINISH
;--- Idiomas ---
!insertmacro MUI_LANGUAGE "Portuguese"
!insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "Spanish"
Function .onInit
!insertmacro MUI_LANGDLL_DISPLAY
InitPluginsDir
GetTempFileName $0
Rename $0 '$PLUGINSDIR\custom.ini'
FunctionEnd
;--------------------------------
;Arquivos a serem instalados
Section "Instalacao"
SetShellVarContext all
SetOutPath "$INSTDIR"
File /r Ficheiros\*.* ; LOCALIZACAO DA APLICACAO DO S-MONITOR
MessageBox MB_OK "O software BDE (Borland Database Engine) será instalado agora"
ExecWait "$INSTDIR\bde_install_Win7_32_e_64.exe"
FileOpen $1 '$INSTDIR\S-monitor.cpy' w
FileWrite $1 "CPY Location=C:\S-Monitor.cpy"
FileClose $1
writeUninstaller $INSTDIR\uninstall.exe
SectionEnd
Section "Uninstall"
MessageBox MB_YESNO "Deseja desinstalar o S-Monitor?" IDYES true IDNO false
true:
SetShellVarContext all
delete $INSTDIR\uninstall.exe
RMDir /R /REBOOTOK $INSTDIR
Goto +2
false:
MessageBox MB_OK "Desinstalação cancelada."
SectionEnd
Function AtalhoDesktop
createShortCut "$DESKTOP\S-Monitor.lnk" "C:\SMonitor.exe"
FunctionEnd
Function showNewCheckbox
${NSD_CreateCheckbox} 120u 110u 100% 10u "&Iniciar o S-Monitor ao terminar a instalação"
Pop $newCheckBox
FunctionEnd
Function launchNewLink
${NSD_GetState} $newCheckBox $0
${If} $0 <> 0
Exec "C:\S-Monitor\Smonitor.exe"
${EndIf}
FunctionEnd
Function CustomCreate
WriteIniStr '$PLUGINSDIR\custom.ini' 'Settings' 'NumFields' '6'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 1' 'Type' 'Label'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 1' 'Left' '5'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 1' 'Top' '5'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 1' 'Right' '-6'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 1' 'Bottom' '60'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 1' 'Text' \
'Escolha a que disco rígido quer associar a sua licença do S-Monitor.\nA instalação do S-Monitor ficará associada de forma permanente ao disco escolhido.\n\nSe desejar transferir a sua licença para outro PC mais tarde, deverá escolher um disco amovível neste passo.\nSe não sabe que opção escolher, deixe seleccionada a opção por defeito.'
StrCpy $R2 0
StrCpy $R0 ''
${GetDrives} "HDD+FDD" GetDrivesCallBack
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'Type' 'DropList'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'Left' '30'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'Top' '64'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'Right' '-31'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'Bottom' '200'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'Flags' 'Notify'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'State' '$R1'
WriteIniStr '$PLUGINSDIR\custom.ini' 'Field 2' 'ListItems' '$R0'
push $0
InstallOptions::Dialog '$PLUGINSDIR\custom.ini'
pop $0
pop $0
FunctionEnd
Function CustomLeave
ReadIniStr $0 '$PLUGINSDIR\custom.ini' 'Settings' 'State'
StrCmp $0 '2' 0 next
ReadIniStr $0 '$PLUGINSDIR\custom.ini' 'Field 2' 'State'
strcpy $R0 $0
StrCpy $0 $0 3
FileOpen $1 '$INSTDIR\S-monitor.cpy' w
FileWrite $1 "CPY Location=$R0S-Monitor.cpy"
FileClose $1
Abort
next:
ReadIniStr $0 '$PLUGINSDIR\custom.ini' 'Field 2' 'State'
StrCpy '$INSTDIR' '$0'
FunctionEnd
Function GetDrivesCallBack
StrCmp $R2 '0' 0 next
StrCpy $R3 '$R4'
StrCpy $R1 '$9'
IntOp $R2 $R2 + 1
next:
StrCpy $R0 '$R0$9|'
Push $0
FunctionEnd

Resources