inno-setuppascalscript

Make unclickable OK button on Inno Setup MsgBox and change to countdown


How to change OK button into a countdown timer like this...

The button should not be clickable and faded. Like inactive window/button/box.

this one:

this one

not this one:

not this one

I use the code code from this question: How to show a message box for a specified time?


Solution

  • There's no built-in function with such functionality. Neither in Inno Setup, nor WinAPI.

    You have to implement the dialog on your own and use a timer to implement the count down.

    [Code]
    
    function SetTimer(hWnd: LongWord; nIDEvent, uElapse: LongWord; 
      lpTimerFunc: LongWord): LongWord; external 'SetTimer@user32.dll stdcall';
    function KillTimer(hWnd: HWND; uIDEvent: LongWord): BOOL;
      external 'KillTimer@user32.dll stdcall';
    
    var
      CountdownButton: TNewButton;
      Countdown: Integer;
    
    procedure UpdateCountDownButtonCaption;
    begin
      CountdownButton.Caption := Format('%d sec', [Countdown]);
    end;
    
    procedure CountdownProc(
      H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
    begin
      Dec(Countdown);
      if Countdown = 0 then
      begin
        CountdownButton.Enabled := True;
        TForm(CountdownButton.Parent).Close;
      end
        else
      begin
        UpdateCountDownButtonCaption;
      end;
    end;
    
    procedure CountdownMessageBoxCloseQuery(Sender: TObject; var CanClose: Boolean);
    begin
      { Prevent the dialog from being close by the X button and Alt-F4 }
      CanClose := CountdownButton.Enabled;
    end;
    
    procedure CountdownMessageBox(Message: string; Seconds: Integer);
    var
      Form: TSetupForm;
      MessageLabel: TLabel;
      Timer: LongWord;
    begin
      Form := CreateCustomForm;
      try
        Form.ClientWidth := ScaleX(256);
        Form.ClientHeight := ScaleY(96);
        Form.Caption := 'Information';
        Form.Position := poMainFormCenter;
        Form.OnCloseQuery := @CountdownMessageBoxCloseQuery;
    
        MessageLabel := TLabel.Create(Form);
        MessageLabel.Top := ScaleY(16);
        MessageLabel.Left := ScaleX(16);
        MessageLabel.AutoSize := True;
        MessageLabel.Caption := Message;
        MessageLabel.Parent := Form;
    
        if CountdownButton <> nil then
          RaiseException('Countdown in progress already');
    
        Countdown := Seconds;
    
        CountdownButton := TNewButton.Create(Form);
        CountdownButton.Parent := Form;
        CountdownButton.Width := ScaleX(88);
        CountdownButton.Height := ScaleY(26);
        CountdownButton.Left :=
          Form.ClientWidth - CountdownButton.Width - ScaleX(18);
        CountdownButton.Top :=
          Form.ClientHeight - CountdownButton.Height - ScaleX(11);
        UpdateCountDownButtonCaption;
        CountdownButton.Name := 'CountdownButton';
        CountdownButton.ModalResult := mrOk;
        CountdownButton.Default := True;
        CountdownButton.Enabled := False;
    
        Timer := SetTimer(0, 0, 1000, CreateCallback(@CountdownProc));
    
        try
          Form.ShowModal();
        finally
          KillTimer(0, Timer);
        end;
      finally
        Form.Free();
        CountdownButton := nil;
      end;
    end;  
    

    For CreateCallback function, you need Inno Setup 6. If you are stuck with Inno Setup 5, you can use WrapCallback function from InnoTools InnoCallback library.


    Use it like:

    CountdownMessageBox('Message here', 10);
    

    Countdown dialog


    Related questions: