Inno Setup Change AppName based on component(s) se

2019-02-16 00:26发布

问题:

I need the installer to show different AppName based on (un)selected components. I tried this:

[Setup]
AppName={code:GetAppName}
AppVersion=1.0
AppVerName=Dagon Video Tools
AppId=Dagon Video Tools
DefaultDirName={sd}\Games\Dagon Video Tools

[Code]
function GetAppName(Value: string): string;
var
  CurPageID: Integer;
Begin
  Result := 'Dagon Video Tools'
  if (CurPageID=wpSelectComponents) and IsComponentSelected('Slasher') and not IsComponentSelected('Frankenstein') then
    begin
      Result := 'Dagon Slasher';
    end;
  if (CurPageID=wpSelectComponents) and IsComponentSelected('Frankenstein') and not IsComponentSelected('Slasher') then
    begin
      Result := 'Dagon Frankenstein';
    end;
  if (CurPageID=wpSelectComponents) and IsComponentSelected('Slasher') and IsComponentSelected('Frankenstein') then
    begin
      Result := 'Dagon Video Tools';
    end;
End;

But, as you can guess, this doesn't work. Is this script incomplete or should it be done in a different way altogether?

回答1:

The AppName directive value is resolved (= your GetAppName is called) immediately after the InitializeSetup (if any) finishes. That is a long before the user is able to change the components.

So you cannot make AppName depend on the selected components.

Some uses of the AppName could be overridden with a custom value though, but not all. See below.


Though, as I know that your question is actually about a setup type, you can do this:

  • Create custom "type" page (like a menu) as the very first one.
  • Once the user selects the "type", restart the installer with a custom switch (e.g. /APPTYPE=slasher) and exit.
  • Once the installer is (re-)run with the /APPTYPE, you know from the beginning, what component/type you are installing and hence you can set the AppName normally.
  • Of course, you skip the custom "type" page.

This is actually a way simpler to implement. The only drawback is that the setup window is "recreated" after the user selects the "type".


This is the original response in case you do not want to use the above solution.

First, your implementation of the GetAppName is wrong. You are using an uninitialized variable CurPageID. And anyway, as mentioned already, the GetAppName is called even before the wizard window is created, so "current page" is irrelevant here.

The correct implementation would be like:

function GetAppName(Value: string): string;
begin
  if IsComponentSelected('Slasher') and not IsComponentSelected('Frankenstein') then
  begin
    Result := 'Dagon Slasher';
  end
    else
  if IsComponentSelected('Frankenstein') and not IsComponentSelected('Slasher') then
  begin
    Result := 'Dagon Frankenstein';
  end
    else
  begin
    Result := 'Dagon Video Tools';
  end;
end;

But this still won't make it working in the AppName directive. We will use it in other contexts though later.

Also note that for your specific installer, you should better use the WizardSetupType(false) function instead of the IsComponentSelected.


FinishedLabel

Just override the Inno Setup default text in CurPageChanged(wpFinished):

procedure CurPageChanged(CurPageID: Integer);
var
  S: string;
begin
  if CurPageID = wpFinished then
  begin
    S := SetupMessage(msgFinishedHeadingLabel);
    StringChange(S, '[name]', GetAppName(''));
    WizardForm.FinishedHeadingLabel.Caption := S;
    WizardForm.AdjustLabelHeight(WizardForm.FinishedHeadingLabel);
    { Ideally we should shift the FinishedLabel up or down here, }
    { if the height of the header changed. }

    { Note that other messages (msgFinishedLabelNoIcons or msgFinishedRestartLabel) }
    { are used in special situations, so this is not a complete solution. }
    S := SetupMessage(msgFinishedLabel);
    StringChange(S, '[name]', GetAppName(''));
    WizardForm.FinishedLabel.Caption := S;
    WizardForm.AdjustLabelHeight(WizardForm.FinishedLabel);
  end;
end;

Add/Remove Programs

That's easy. There's the UninstallDisplayName directive for this, which is resolved only during the actual installation, when we already know the selected components. So we can use your (fixed) GetAppName here:

[Setup]
UninstallDisplayName={code:GetAppName}

Are you sure you want to completely remove AppName and all of its components?

You cannot change that. You better use some generic name in the AppName so that this message works for any component.

Or make the message not mention the application name at all:

[Messages]
ConfirmUninstall=Are you sure you want to completely remove this game?

Alternatively remove the message completely:
Can I disable uninstall confirmation message?
and optionally replace it with your own message implemented in the InitializeUninstall event function.


Please wait while AppName is removed from your computer

The same solution as for the WizardForm.FinishedLabel. Just use the UninstallProgressForm.PageDescriptionLabel from the InitializeUninstallProgressForm.


AppName was successfully removed from your computer

Similar as with the "Are you sure you want to completely remove AppName and all of its components?"

Either make the AppName generic. Or disable the message with "silent" mode and implement your own message in the CurUninstallStepChanged(usPostUninstall).


For a similar discussion, see also Changing AppName and AppDir depending on language in Inno Setup.