Saturday, August 25, 2012

Inno Setup, Part 8. Creating custom wizard page.

Today we will describe a process of creating custom wizard page in program installer. Though Inno Setup suggests pages which will cover your needs in most of the cases, sometimes you will need to create your own page during installation process. Custom page can be created in [Code] section in InitializeWizard function:

[Code]
procedure InitializeWizard();
begin
  authentication_form_CreatePage(wpLicense);
end;

wpLicense argument means that our custom page will be displayed after standard license page during installation process. All standard wizard pages have their predefined IDs. For instance, welcome page have ID equal to wpWelcome. Now let’s look at the code which is creating custom page. First we need to define some variables which will be used:

var
  Label1: TLabel;
  Label2: TLabel;
  Label3: TLabel;
  Label4: TLabel;
  ServerNameEdit: TEdit;
  WindowsRadioButton: TRadioButton;
  SqlRadioButton: TRadioButton;
  UserEdit: TEdit;
  PasswordEdit: TEdit;

And this is the function itself. In it you will need to create all the necessary controls like labels, buttons, etc.:

function authentication_form_CreatePage(PreviousPageId: Integer): Integer;
var
  Page: TWizardPage;
begin
  Page := CreateCustomPage(
    PreviousPageId,
    ExpandConstant('{cm:authentication_form_Caption}'),
    ExpandConstant('{cm:authentication_form_Description}')
  );

  Label1 := TLabel.Create(Page);
  with Label1 do
  begin
    Parent := Page.Surface;
    Caption := ExpandConstant('{cm:authentication_form_Label1_Caption0}');
    Left := ScaleX(16);
    Top := ScaleY(0);
    Width := ScaleX(84);
    Height := ScaleY(17);
  end;
 
  Label2 := TLabel.Create(Page);
  with Label2 do
  begin
    Parent := Page.Surface;
    Caption := ExpandConstant('{cm: authentication_form_Label2_Caption0}');
    Left := ScaleX(16);
    Top := ScaleY(56);
    Width := ScaleX(300);
    Height := ScaleY(17);
  end;
 
  Label3 := TLabel.Create(Page);
  with Label3 do
  begin
    Parent := Page.Surface;
    Caption := ExpandConstant('{cm: authentication_form_Label3_Caption0}');
    Left := ScaleX(56);
    Top := ScaleY(136);
    Width := ScaleX(70);
    Height := ScaleY(17);
  end;
 
  Label4 := TLabel.Create(Page);
  with Label4 do
  begin
    Parent := Page.Surface;
    Caption := ExpandConstant('{cm: authentication_form_Label4_Caption0}');
    Left := ScaleX(56);
    Top := ScaleY(168);
    Width := ScaleX(63);
    Height := ScaleY(17);
  end;
 
  ServerNameEdit := TEdit.Create(Page);
  with ServerNameEdit do
  begin
    Parent := Page.Surface;
    Left := ScaleX(16);
    Top := ScaleY(24);
    Width := ScaleX(257);
    Height := ScaleY(25);
    TabOrder := 0;
    Text := ExpandConstant('{cm: authentication_form_ServerNameEdit_Text0}');
  end;
 
  WindowsRadioButton := TRadioButton.Create(Page);
  with WindowsRadioButton do
  begin
    Parent := Page.Surface;
    Caption := ExpandConstant('{cm: authentication_form_WindowsRadioButton_Caption0}');
    Left := ScaleX(16);
    Top := ScaleY(88);
    Width := ScaleX(225);
    Height := ScaleY(17);
    Checked := True;
    TabOrder := 1;
    TabStop := True;
  end;
 
  SqlRadioButton := TRadioButton.Create(Page);
  with SqlRadioButton do
  begin
    Parent := Page.Surface;
    Caption := ExpandConstant('{cm: authentication_form_SqlRadioButton_Caption0}');
    Left := ScaleX(16);
    Top := ScaleY(112);
    Width := ScaleX(193);
    Height := ScaleY(17);
    TabOrder := 2;
  end;
 
  UserEdit := TEdit.Create(Page);
  with UserEdit do
  begin
    Parent := Page.Surface;
    Left := ScaleX(136);
    Top := ScaleY(136);
    Width := ScaleX(121);
    Height := ScaleY(25);
    TabOrder := 3;
    Text := ExpandConstant('{cm: authentication_form_UserEdit_Text0}');
  end;
 
  PasswordEdit := TEdit.Create(Page);
  with PasswordEdit do
  begin
    Parent := Page.Surface;
    Left := ScaleX(136);
    Top := ScaleY(168);
    Width := ScaleX(121);
    Height := ScaleY(25);
    TabOrder := 4;
    PasswordChar := '*';
    Text := ExpandConstant('{cm: authentication_form_PasswordEdit_Text0}');
  end;

  with Page do
  begin
    OnNextButtonClick := @authentication_form_NextButtonClick;
  end;

  Result := Page.ID;
end;

Finally we will need handler for Next button click:

function authentication_form_NextButtonClick(Page: TWizardPage): Boolean;
begin
  Result := True;
  if ServerNameEdit.Text <> ''   then
    begin
       if SqlRadioButton.Checked then
       begin
          if UserEdit.Text = ''  then
          begin
             MsgBox('You should enter user name', mbError, MB_OK);
             Result := False;
          end
          else
          begin
            if PasswordEdit.Text = '' then
            begin
               MsgBox('You should enter password', mbError, MB_OK);
               Result := False;
            end
          end
       end
    end
    else
    begin
    MsgBox('You should enter path to SQL Server Database', mbError, MB_OK);
    Result := False;
    end;
end;

The text labels and messages need to be defined in special section:

[CustomMessages]
authentication_form_Caption=SQL Server Database Setup
authentication_form_Description=Choose SQL Server database you will be using (ask your administrator about its parameters)
authentication_form_Label1_Caption0=Server Name:
authentication_form_Label2_Caption0=Enter Path to SQL Server (e.g. .\SQLEXPRESS; DEVSERVER)
authentication_form_Label3_Caption0=User name:
authentication_form_Label4_Caption0=Password:
authentication_form_ServerNameEdit_Text0=
authentication_form_WindowsRadioButton_Caption0=Use Windows Authentication
authentication_form_SqlRadioButton_Caption0=Use SQL Authentication
authentication_form_UserEdit_Text0=
authentication_form_PasswordEdit_Text0=

After such a long work you want to see probably what we will receive at the end? Such a window:

As you can see to receive this nice window you have to write a large amount of code and this is the case where some automated tool like ISTool can be helpful for you.

4 comments:

  1. no work Starting compile. [mardi, mars 31 2015 at 10:00:03]
    Compiling script with Inno Setup 5.2.0 [ISDLLCompileScriptA]

    [PreCompile] Processing.
    [PreCompile] Processing is still being tested.
    [PreCompile] Processing finished.

    Parsing [Setup] section, line 8
    Parsing [Setup] section, line 9
    Parsing [Setup] section, line 10
    Parsing [Setup] section, line 11
    Parsing [Setup] section, line 12
    Parsing [Setup] section, line 13
    Parsing [Setup] section, line 14
    Parsing [Setup] section, line 15
    Parsing [Setup] section, line 16
    Parsing [Setup] section, line 17
    Parsing [Setup] section, line 18
    Parsing [Setup] section, line 19
    Parsing [Setup] section, line 20
    Parsing [Setup] section, line 21
    Parsing [Setup] section, line 22
    Parsing [Setup] section, line 23
    Reading file (LicenseFile)
    Reading file (InfoBeforeFile)
    Reading file (InfoAfterFile)
    Reading file (WizardImageFile)
    File: C:\Program Files\Inno Setup 5\WIZMODERNIMAGE.BMP
    Reading file (WizardSmallImageFile)
    File: C:\Program Files\Inno Setup 5\WIZMODERNSMALLIMAGE.BMP
    Reading default messages from Default.isl
    Parsing [Languages] section, line 26
    File: C:\Program Files\Inno Setup 5\Default.isl
    Parsing [Languages] section, line 27
    File: C:\Program Files\Inno Setup 5\Languages\Basque.isl
    Parsing [Languages] section, line 28
    File: C:\Program Files\Inno Setup 5\Languages\BrazilianPortuguese.isl
    Parsing [Languages] section, line 29
    File: C:\Program Files\Inno Setup 5\Languages\Catalan.isl
    Parsing [Languages] section, line 30
    File: C:\Program Files\Inno Setup 5\Languages\Czech.isl
    Parsing [Languages] section, line 31
    File: C:\Program Files\Inno Setup 5\Languages\Danish.isl
    Parsing [Languages] section, line 32
    File: C:\Program Files\Inno Setup 5\Languages\Dutch.isl
    Parsing [Languages] section, line 33
    File: C:\Program Files\Inno Setup 5\Languages\Finnish.isl
    Parsing [Languages] section, line 34
    File: C:\Program Files\Inno Setup 5\Languages\French.isl
    Parsing [Languages] section, line 35
    File: C:\Program Files\Inno Setup 5\Languages\German.isl
    Parsing [Languages] section, line 36
    File: C:\Program Files\Inno Setup 5\Languages\Hebrew.isl
    Parsing [Languages] section, line 37
    File: C:\Program Files\Inno Setup 5\Languages\Hungarian.isl
    Parsing [Languages] section, line 38
    File: C:\Program Files\Inno Setup 5\Languages\Italian.isl
    Parsing [Languages] section, line 39
    File: C:\Program Files\Inno Setup 5\Languages\Norwegian.isl
    Parsing [Languages] section, line 40
    File: C:\Program Files\Inno Setup 5\Languages\Polish.isl
    Parsing [Languages] section, line 41
    File: C:\Program Files\Inno Setup 5\Languages\Portuguese.isl
    Parsing [Languages] section, line 42
    File: C:\Program Files\Inno Setup 5\Languages\Russian.isl
    Parsing [Languages] section, line 43
    File: C:\Program Files\Inno Setup 5\Languages\Slovak.isl
    Parsing [Languages] section, line 44
    File: C:\Program Files\Inno Setup 5\Languages\Slovenian.isl
    Parsing [Languages] section, line 45
    File: C:\Program Files\Inno Setup 5\Languages\Spanish.isl
    Parsing [LangOptions], [Messages], and [CustomMessages] sections
    Messages in script file
    Reading [Code] section
    Parsing [Tasks] section, line 48
    Parsing [Icons] section, line 55
    Parsing [Icons] section, line 56
    Parsing [Run] section, line 59
    Parsing [Files] section, line 51
    Compiling [Code] section
    Compiler Error!
    Line 67: Column 1: Unknown identifier 'authentication_form_CreatePage'

    ReplyDelete
    Replies
    1. Thanks for your comment. From the error message Inno Setup can't find function with the name authentication_form_CreatePage. Could you please check it is there in [Code] section?

      If you will check the post, this function is important for creating custom controls.

      Delete
  2. Please, remove space symbol after "cm:" in custom messages (for ex. '{cm: authentication_form_WindowsRadioButton_Caption0}'), because with space it doesn't work

    ReplyDelete
  3. If you see the error about the missing function, this is because it has to be declared *before* its call in the procedure.
    So move the procedure at the end of the code, and the code should compile.

    ReplyDelete