我们实际上有一个设置,在安装过程中有很多组件选择,我们希望在客户重新安装我们的软件时禁用已安装的组件(或使其变为灰色/固定)。
例如,在第一次安装期间,我们有 3 个组件,如下所示:
Component
* International
* French
* German
首次安装时,可以选择所有组件。
认识到选择“德语”包,当用户重新安装产品(使用相同的安装程序)以获得新的语言包时,我们希望有类似的东西:
Component
* International
* French
* German (already installed)
其中“德语”不能选择...
有没有办法用 Inno Setup 来做到这一点?
我找到了InnoSetup:升级时禁用组件页面,但该示例禁用了整个组件页面,我想保留它。
编辑:
这适用于 2 个安装。但是,如果我进行第三次安装(用于安装最后一个组件),则安装程序将采用第二次安装的组件,而不是第一个安装的组件。
我认为这是因为安装程序覆盖了第一次安装的注册表项,因此看不到早期安装的组件...
这是首次安装时的日志和注册表项(选择英文):
2016-03-22 13:57:56.913 New install de Bim
这是第二次安装时的日志和注册表项(英语为灰色且无法选择,法语已选择):
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.
这是第三次安装的日志和注册表项
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.
很明显,inno-setup 在每次安装后都会写入
Software\Microsoft\Windows\CurrentVersion\Uninstall\AppId_is1\Inno Setup: Selected Components
,这就是为什么它只适用于第二次安装,但不记得在第三次安装期间在第一次安装中选择了组件。
您可以从注册表值中提取已安装组件的列表
Software\Microsoft\Windows\CurrentVersion\Uninstall\AppId_is1\Inno Setup: Selected Components
问题是列表使用组件名称,并且无法将名称映射到复选框,因为仅以编程方式公开描述(另请参阅如何允许在 Inno Setup 中仅安装特定组件?
幸运的是,之前安装的组件将由 Inno Setup 本身进行检查。因此,最简单的解决方案是禁用所有最初检查的组件。如果您在默认情况下选中的升级中添加新组件,则会破坏这一点。
WizardSelectedComponents
支持功能,它可以返回所选组件名称和描述的列表。因此它可用于将描述映射到名称并映射回来。但仅适用于选定的组件。尽管这对于您的特定目的来说应该足够了。请参阅我的代码中的 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;