Inno Setup - Language selector with VCL Styles

前端 未结 2 1828
情歌与酒
情歌与酒 2020-11-27 07:15

Is there any way to use language selector (Inno Setup) with VCL Styles? How?

相关标签:
2条回答
  • 2020-11-27 07:52

    The "Select Setup Language" dialog displays before the InitializeSetup event function is called. So you cannot load the skin for the dialog.


    As a workaround, you can implement your own "language" dialog, and display that from the InitializeSetup. This way the custom dialog will be skinned. Once a user selects a language, you restart the installer with the /LANG switch to load the selected language.

    Make sure you disable the standard language dialog by setting the ShowLanguageDialog to no.

    [Setup]
    ShowLanguageDialog=no
    
    [Files]
    Source: "skin.vsf"; Flags: dontcopy
    Source: "VclStylesInno.dll"; Flags: dontcopy
    
    [Languages]
    Name: "en"; MessagesFile: "compiler:Default.isl"
    Name: "cs"; MessagesFile: "compiler:Languages\Czech.isl"
    
    [Code]
    
    procedure LoadVCLStyle(VClStyleFile: String);
      external 'LoadVCLStyleW@files:VclStylesInno.dll stdcall setuponly';
    procedure UnLoadVCLStyles;
      external 'UnLoadVCLStyles@files:VclStylesInno.dll stdcall setuponly';
    
    function ShellExecute(hwnd: HWND; lpOperation: string; lpFile: string;
      lpParameters: string; lpDirectory: string; nShowCmd: Integer): THandle;
      external 'ShellExecuteW@shell32.dll stdcall';
      
    procedure SelectLanguage();
    var
      LanguageForm: TSetupForm;
      CancelButton: TNewButton;
      OKButton: TNewButton;
      LangCombo: TNewComboBox;
      SelectLabel: TNewStaticText;
      Languages: TStrings;
      Params: string;
      Instance: THandle;
      P, I: Integer;
      S, L: string;
    begin
      Languages := TStringList.Create();
    
      Languages.Add('en=English');
      Languages.Add('cs='+#$010C+'e'+#$0161+'tina');
    
      LanguageForm := CreateCustomForm;
    
      LanguageForm.Caption := SetupMessage(msgSelectLanguageTitle);
      LanguageForm.ClientWidth := ScaleX(297);
      LanguageForm.ClientHeight := ScaleY(125);
      LanguageForm.BorderStyle := bsDialog;
    #if Ver < 0x06000000
      LanguageForm.Center;
    #endif
    
      CancelButton := TNewButton.Create(LanguageForm);
      CancelButton.Parent := LanguageForm;
      CancelButton.Top := ScaleY(93);
      CancelButton.Width := ScaleY(75);
      CancelButton.Left := LanguageForm.ClientWidth - CancelButton.Width - ScaleX(16);
      CancelButton.Height := ScaleY(23);
      CancelButton.TabOrder := 3;
      CancelButton.ModalResult := mrCancel;
      CancelButton.Caption := SetupMessage(msgButtonCancel);
    
      OKButton := TNewButton.Create(LanguageForm);
      OKButton.Parent := LanguageForm;
      OKButton.Top := CancelButton.Top;
      OKButton.Width := CancelButton.Width;
      OKButton.Left := CancelButton.Left - OKButton.Width - ScaleX(8);
      OKButton.Height := CancelButton.Height;
      OKButton.Caption := SetupMessage(msgButtonOK);
      OKButton.Default := True
      OKButton.ModalResult := mrOK;
      OKButton.TabOrder := 2;
    
      LangCombo := TNewComboBox.Create(LanguageForm);
      LangCombo.Parent := LanguageForm;
      LangCombo.Left := ScaleX(16);
      LangCombo.Top := ScaleY(56);
      LangCombo.Width := LanguageForm.ClientWidth - ScaleX(16) * 2;
      LangCombo.Height := ScaleY(21);
      LangCombo.Style := csDropDownList;
      LangCombo.DropDownCount := 16;
      LangCombo.TabOrder := 1;
    
      SelectLabel := TNewStaticText.Create(LanguageForm);
      SelectLabel.Parent := LanguageForm;
      SelectLabel.Left := LangCombo.Left;
      SelectLabel.Top := ScaleY(8);
      SelectLabel.Width := LangCombo.Width;
      SelectLabel.Height := ScaleY(39);
      SelectLabel.AutoSize := False
      SelectLabel.Caption := SetupMessage(msgSelectLanguageLabel);
      SelectLabel.TabOrder := 0;
      SelectLabel.WordWrap := True;
    
      for I := 0 to Languages.Count - 1 do
      begin
        P := Pos('=', Languages.Strings[I]);
        L := Copy(Languages.Strings[I], 0, P - 1);
        S := Copy(Languages.Strings[I], P + 1, Length(Languages.Strings[I]) - P);
        LangCombo.Items.Add(S);
        if L = ActiveLanguage then
          LangCombo.ItemIndex := I;
      end;
    
      { Restart the installer with the selected language }
      if LanguageForm.ShowModal = mrOK then
      begin
        { Collect current instance parameters }
        for I := 1 to ParamCount do
        begin
          S := ParamStr(I);
          { Unique log file name for the elevated instance }
          if CompareText(Copy(S, 1, 5), '/LOG=') = 0 then
          begin
            S := S + '-localized';
          end;
          { /SL5 switch is an internal switch used to pass data }
          { from the master Inno Setup process to the child process. }
          { As we are starting a new master process, we have to remove it. }
          if CompareText(Copy(S, 1, 5), '/SL5=') <> 0 then
          begin
            Params := Params + AddQuotes(S) + ' ';
          end;
        end;
    
        L := Languages.Strings[LangCombo.ItemIndex];
        P := Pos('=', L);
        L := Copy(L, 0, P-1);
    
        { ... and add selected language }
        Params := Params + '/LANG=' + L;
    
        Instance := ShellExecute(0, '', ExpandConstant('{srcexe}'), Params, '', SW_SHOW);
        if Instance <= 32 then
        begin
          S := 'Running installer with the selected language failed. Code: %d';
          MsgBox(Format(S, [Instance]), mbError, MB_OK);
        end;
      end;
    end;
    
    function InitializeSetup(): Boolean;
    var
      Language: string;
    begin
      ExtractTemporaryFile('skin.vsf');
      LoadVCLStyle(ExpandConstant('{tmp}\skin.vsf'));
    
      Result := True;
    
      if WizardSilent then
      begin
        Log('Silent installation, keeping the default language');
      end
        else
      begin
        Language := ExpandConstant('{param:LANG}');
        if Language = '' then
        begin
          Log('No language specified, showing language dialog');
          SelectLanguage();
          Result := False;
          Exit;
        end
          else
        begin
          Log('Language specified, proceeding with installation');
        end;
      end;
    end;
    
    procedure DeinitializeSetup();
    begin
      UnLoadVCLStyles;
    end;
    


    Installer re-launch code is based on Make Inno Setup installer request privileges elevation only when needed.


    Note that the code probably needs tweaking, if you want to allow parent process to wait for the installation to complete. Though in that case you are probably going to use the silent installation, what the code can handle correctly.

    0 讨论(0)
  • 2020-11-27 07:55

    You need to recompile Inno Setup from source.

    Find this code in Main.pas file and move this section after CodeRunner and InitializeSetup.

    { Show "Select Language" dialog if necessary }
      if ShowLanguageDialog and (Entries[seLanguage].Count > 1) and
         not InitSilent and not InitVerySilent then begin
        if not AskForLanguage then
          Abort;
      end;
    

    0 讨论(0)
提交回复
热议问题