nsDialogs::Show accepts ENTER key even if all buttons from UI are destroyed

275 Views Asked by At

I have a small bootstrapper with custom UI, which contains two pages, one to configure the install, and the other showing a progressbar for the download and install of the payload. My problem: If the user presses Enter key when in the second page, the installer exits, even if it didn't finish installing.

I removed all the controls I could from the UI with:

GetDlgItem $1 $HWNDPARENT 1 //(2, and 3)
System::Call `User32::DestroyWindow(i $1)`

in the onGuiInit function, and the first page ignores enter and space keys now, but the second page still exits on Enter key. I have no other components on that page except some labels, a progressbar, and a slideshow (nsisSlideshow plugin). In the background I have a thread which downloads and installs the payload.

The pages are declared like this:

Page Custom Options_Show Options_Leave
Page Custom Progress_Show Progress_Leave

So, long story short, when I press enter, the nsDialogs::Show function returns, killing the installer.

Any way I can stop it from doing this?

2

There are 2 best solutions below

1
Anders On BEST ANSWER

You really should try to stop forward page changes by calling Abort in the page leave callback function.

NSIS only blocks clicks from buttons that exist and are disabled.

!include nsDialogs.nsh
Page Custom Options_Show #Options_Leave
Page Custom Progress_Show #Progress_Leave

Function DisableBottomButtons
GetDlgItem $0 $hwndparent 1
ShowWindow $0 0
EnableWindow $0 0
GetDlgItem $0 $hwndparent 2
ShowWindow $0 0
EnableWindow $0 0
GetDlgItem $0 $hwndparent 3 
ShowWindow $0 0
EnableWindow $0 0
FunctionEnd


Function Options_Show
nsDialogs::Create 1018
Pop $0
${NSD_CreateButton} 0 20 100% 12u "Go to next page"
Pop $0
${NSD_OnClick} $0 GoToNextPage
Call DisableBottomButtons
nsDialogs::Show
FunctionEnd

Function GoToNextPage
GetDlgItem $0 $hwndparent 1
EnableWindow $0 1
SendMessage $hwndparent ${WM_COMMAND} 1 0
FunctionEnd


Function Progress_Show
nsDialogs::Create 1018
Pop $0
${NSD_CreateButton} 0 20 100% 12u "Exit"
Pop $0
${NSD_OnClick} $0 ExitApp
Call DisableBottomButtons
nsDialogs::Show
FunctionEnd

Function ExitApp
MessageBox mb_ok "Bye"
; Faking a click on Next/Close will not work when the button is disabled, 
; this uses a slightly ugly trick to bypass that. GoToNextPage does it properly.
!define /math WM_NOTIFY_OUTER_NEXT ${WM_USER} + 0x8
SendMessage $hwndparent ${WM_NOTIFY_OUTER_NEXT} 1 0
FunctionEnd
7
Serge Z On

First, small code snippet:

!macro EnableNextButtonM IsEnable
    Push $1
    GetDlgItem $1 $HWNDPARENT 1 ;next button
    EnableWindow $1 ${IsEnable}
    Pop $1
!macroend
!define EnableNextButton "!insertmacro EnableNextButtonM"

Then, in function Progress_Show you should call

${EnableNextButton} 0

before

nsDialogs::Show

to disable Next button before it will be shown. After download completion (at the download callback) call

${EnableNextButton} 1

to enable it again.

You variant with .onGuiInit does not work because it calls once - before first page will be shown. But every next page will be created dynamically again, thus, all UI page must be implemented into page custom -Pre function.