Inno Setup: Disable already installed components on upgrade

被刻印的时光 ゝ 提交于 2019-12-04 18:55:50

You can extract list of installed components from registry value

Software\Microsoft\Windows\CurrentVersion\Uninstall\AppId_is1\Inno Setup: Selected Components

The problem is that the list uses component names and there's no way to map the names to the checkboxes as only descriptions are exposed programmatically (see also How to allow to only install specific components in InnoSetup?

Luckily the previously installed components will be checked by Inno Setup itself. So the easiest solution is to disable all initially checked components. This will break though if you add a new component in the upgrade that is checked by default.

Another way is to use WizardSelectedComponents support function that can return both list of selected component names and descriptions. So it can be used to map descriptions to names and back. But only for selected components. Though that should be enough for your specific purpose. See SelectedComponentDescriptionToName in my code.

A limitation is that the description must be unique, otherwise the mapping fails. So you cannot for example have multiple "Deutsch" subcomponents of different parent components (that would require more complicated code and won't work at all if the parent component has checkablealone flag)

#define AppId "myapp"
#define InnoSetupReg \
  "Software\Microsoft\Windows\CurrentVersion\Uninstall\" + AppId + "_is1"
#define InnoSetupSelectedComponentsReg "Inno Setup: Selected Components"

[Setup]
AppId={#AppId}
...

[Code]

function ExtractToken(var S: string): string;
var
  P: Integer;
begin
  P := Pos(',', S);
  if P > 0 then
  begin
    Result := Copy(S, 1, P - 1);
    Delete(S, 1, P);
  end
    else
  begin
    Result := S;
    S := '';
  end;
end;

function SelectedComponentDescriptionToName(Description: string): string;
var
  Descriptions: string;
  Names: string;
begin
  Descriptions := WizardSelectedComponents(True);
  Names := WizardSelectedComponents(False);

  while Descriptions <> '' do
  begin
    Result := ExtractToken(Names);
    if RemoveQuotes(ExtractToken(Descriptions)) = Description then
    begin
      Exit;
    end;
  end;

  Result := '';
end;

procedure InitializeWizard();
var
  Upgrade: Boolean;
  SelectedComponents: string;
  Component: string;
  Name: string;
  I: Integer;
begin
  Upgrade :=
    RegQueryStringValue(HKCU, ExpandConstant('{#InnoSetupReg}'), 
      '{#InnoSetupSelectedComponentsReg}', SelectedComponents) or
    RegQueryStringValue(HKLM, ExpandConstant('{#InnoSetupReg}'),
      '{#InnoSetupSelectedComponentsReg}', SelectedComponents);

  if not Upgrade then
  begin
    Log('New install');
  end
    else
  begin
    Log(Format('Upgrading, previously installed components are [%s]', [
      SelectedComponents]));

    while SelectedComponents <> '' do
    begin
      Component := ExtractToken(SelectedComponents);

      Log(Format('Found installed component [%s]', [Component]));

      for I := 0 to WizardForm.ComponentsList.Items.Count - 1 do
      begin
        if WizardForm.ComponentsList.State[I] = cbChecked then
        begin
          Name :=
            SelectedComponentDescriptionToName(
              WizardForm.ComponentsList.ItemCaption[I]);

          if Name = Component then
          begin
            Log(Format('Disabling installed component [%s] as [%s] at %d', [
              Name, WizardForm.ComponentsList.ItemCaption[I], I]));
            WizardForm.ComponentsList.ItemEnabled[I] := False;
          end;
        end;
      end;
    end;
  end;
end;
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!