Inno设置:在升级时禁用已安装的组件

时间:2016-02-17 11:03:55

标签: inno-setup pascalscript

我们实际上有一个设置,在安装过程中有很多组件选择,我们希望在客户重新安装我们的软件时禁用已安装的组件(或使其灰色/固定)。

例如,在第一次安装时,我们有3个这样的组件:

Component
* International
* French
* German

首次安装时,可以选择所有组件。

认识到选择“德语”包,当用户重新安装产品(使用相同的安装程序)以获得新的语言包时,我们希望有类似的东西:

Component
* International
* French
* German (already installed)

无法选择“德语”......

Inno Setup有没有办法做到这一点?

我找到了InnoSetup: Disable components page on upgrade,但该示例禁用了整个组件页面,我想保留它。

编辑

这适用于2次安装。但是,如果我进行第三次安装(用于安装最后一个组件),则安装程序将采用第二次安装的组件,但不是第一次安装。

我认为这是因为安装程序会覆盖第一次安装的注册表项,因此没有看到早期安装的组件......

这是首次安装时的日志和注册表项(选择英语):

after first install

2016-03-22 13:57:56.913   New install de Bim

这是第二次安装时的日志和注册表项(英语为灰色,无法选择,法语被选中):

after second install

Created temporary directory: C:\Users\mea\AppData\Local\Temp\is-QV8N6.tmp
2016-03-22 14:00:54.354   Upgrading, previously installed components are [languagepacks,languagepacks\english,canecorevit,canecorevit\2016]
2016-03-22 14:00:54.354   Found installed component [languagepacks]
2016-03-22 14:00:54.354   Disabling installed component [languagepacks] as [Content] at 0
2016-03-22 14:00:54.355   Found installed component [languagepacks\english]
2016-03-22 14:00:54.355   Disabling installed component [languagepacks\english] as [Pack International] at 1
2016-03-22 14:00:54.355   Found installed component [canecorevit]
2016-03-22 14:00:54.356   Found installed component [canecorevit\2016]
2016-03-22 14:00:54.356   Disabling installed component [canecorevit\2016] as [REVIT 2016] at 5
2016-03-22 14:02:48.691   Message box (Yes/No):
                          L'assistant d'installation a détecté que les composants suivants sont déjà installés sur votre système :

                          Pack International

                          Désélectionner ces composants ne les désinstallera pas pour autant.

                          Voulez-vous continuer malgré tout ?
2016-03-22 14:02:49.808   User chose Yes.
2016-03-22 14:02:56.000   Starting the installation process.

这是第三次安装的日志和注册表项

enter image description here

Created temporary directory: C:\Users\mea\AppData\Local\Temp\is-J7G5A.tmp
2016-03-22 14:07:41.582   Upgrading, previously installed components are [languagepacks,languagepacks\french,canecorevit,canecorevit\2016]
2016-03-22 14:07:41.583   Found installed component [languagepacks]
2016-03-22 14:07:41.583   Disabling installed component [languagepacks] as [Content] at 0
2016-03-22 14:07:41.583   Found installed component [languagepacks\french]
2016-03-22 14:07:41.584   Disabling installed component [languagepacks\french] as [Pack France] at 2
2016-03-22 14:07:41.584   Found installed component [canecorevit]
2016-03-22 14:07:41.584   Found installed component [canecorevit\2016]
2016-03-22 14:07:41.585   Disabling installed component [canecorevit\2016] as [REVIT 2016] at 5
2016-03-22 14:08:14.122   Message box (Yes/No):
                          L'assistant d'installation a détecté que les composants suivants sont déjà installés sur votre système :

                          Pack France

                          Désélectionner ces composants ne les désinstallera pas pour autant.

                          Voulez-vous continuer malgré tout ?
2016-03-22 14:08:15.132   User chose Yes.

显然,在Software\Microsoft\Windows\CurrentVersion\Uninstall\AppId_is1\Inno Setup: Selected Components上每次安装后都会创建inno-setup,这就是为什么它只适用于第二次安装,但是不记得第一次安装时会选择该组件。

1 个答案:

答案 0 :(得分:1)

您可以从注册表值

中提取已安装组件的列表
Software\Microsoft\Windows\CurrentVersion\Uninstall\AppId_is1\Inno Setup: Selected Components

问题是该列表使用组件名称,并且无法将名称映射到复选框,因为只有编程方式公开了描述(另请参阅How to allow to only install specific components in InnoSetup?)。

幸运的是,Inno Setup本身将检查以前安装的组件。因此,最简单的解决方案是禁用所有初始检查的组件。如果在默认情况下选中的升级中添加新组件,这将会破坏。

另一种方法是使用WizardSelectedComponents support function,它可以返回所选组件名称和描述的列表。因此,它可用于将描述映射到名称和返回。但仅适用于选定的组件。虽然这应该足以满足您的特定目的。请参阅我的代码中的SelectedComponentDescriptionToName

限制是描述必须是唯一的,否则映射将失败。因此,您不能拥有不同父组件的多个“Deutsch”子组件(这将需要更复杂的代码,如果父组件具有checkablealone标志,则根本不起作用)

#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;