arrays - 创新设置: Single installer that reads names from an INI file and creates an installation for each name

标签 arrays inno-setup pascalscript

我正在使用 Pascal Script 函数来读取和检测文件的数组中有多少个名称。当它确定名称数量时,我想要一个 #for 循环来迭代该数量。

我可以使用 Pascal Script 读取和检测名称的数量。问题是,我不知道如何在名称计数过程之后设置 numberOfElements 变量的值。必须将其设置为刚刚使用 Pascal Script 函数读取的名称数量。

这里是一些示例代码:

#define numberOfElements

#sub CreateSubInstallation
[Languages]
//code ommitted

[Files]
//code ommitted

[Run]
//code ommitted

#endsub
#for {i = 0; i < numberOfElements; i++} CreateSubInstallation

采用不同的方法也可以。我只想从文件中读取多个名称,然后根据名称数量制作安装副本。因此,每个名称都有其自己的安装。更详细地说,每个名称都有自己的:目录、子目录和文件中的变量,这些文件会将名称“注入(inject)”到其中。

以下是 INI 文件的格式:

[Customer]
customers={"customerName1","customerName2"}

以下是使用 Pascal Script 读取和检测名称的代码:

{ Get the customer names from file }
function GetCustomersFromFile(fileName : string): string;
var
  lines: TArrayOfString;
  amountOfLines,i: integer;
  tempResult: string;
begin
  tempResult := '';
  if LoadStringsFromFile(fileName, lines) then
  begin
    amountOfLines := GetArrayLength(amountOfLines);
    { Keep reading lines until the end of the file is reached }
    for i := 0 to amountOfLines - 1 do
    begin
      if (Pos('customers', lines[i]) = 1) then
        tempResult := lines[i];
    end;

    { if not found return -1 }
    if (tempResult = '') then
      { this result is for debugging and }
      { will have no impact on the array population process }
      tempResult := '-1';

    Result := tempResult;
  end;
end;

{ Count the number of elements present in the array in the file }
{ Done for tempArray initilization }
function CountNumberOfStringElements(line : string): integer;
const 
  chars = ['0'..'9', 'a'..'z', 'A'..'Z'];
var
  ignoreCommas: Boolean;
  numElements, numValidText: integer;
  i: integer;
begin
  ignoreCommas := false;
  numValidText := 0;
  numElements := 0;
  { Loop through text }
  for i := 0 to Length(line) - 1 do
  begin
    if (line[i] = '"') then
      ignoreCommas := (NOT ignoreCommas);

    if ((line[i]) IN chars AND (ignoreCommas)) then
      Inc(numValidText);

    if((line[i] = ',') AND (NOT ignoreCommas) )then
      Inc(numElements);
  end;

  if (numElements >= 1) then
    result := numElements + 1
  else if ((numElements = 0) AND (numValidText > 0)) then
    result := 1
  else if ((numElements = 0) AND (numValidText = 0)) then
    result := 0;
end;

这本质上就是我希望安装程序执行的操作,只是一个非常精简的版本。

[Setup]
AppName=My Program
AppVersion=1.5
WizardStyle=modern
DefaultDirName={autopf}\My Program
DefaultGroupName=My Program
UninstallDisplayIcon={app}\MyProg.exe
Compression=lzma2
SolidCompression=yes
OutputDir=userdocs:Inno Setup Examples Output
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64

[Files]
Source: "MyProg-x64.exe"; DestDir: "{app}/customer1/"; DestName: "MyProg.exe"
Source: "MyProg.chm"; DestDir: "{app}/customer1/"
Source: "Readme.txt"; DestDir: "{app}/customer1/"; Flags: isreadme

Source: "MyProg-x64.exe"; DestDir: "{app}/customer2/"; DestName: "MyProg.exe"
Source: "MyProg.chm"; DestDir: "{app}/customer2/"
Source: "Readme.txt"; DestDir: "{app}/customer2/"; Flags: isreadme

[Icons]
Name: "{group}\My Program"; Filename: "{app}\MyProg.exe"

请注意之所以这样构造是因为它们是服务。每项服务最终都会包含更多与客户相关的内容。整个安装过程必须使用 .exe 完成,而删除过程则必须使用不同但单一的 .exe 完成。

最佳答案

你的问题很不清楚。但我会尽力给你一些答案。

如果我理解正确的话,您希望在 INI 文件中为每个客户部署相同的文件集。如果您需要在运行/安装时读取 INI 文件(这是可能的,如果您在编译时读取 INI 文件),则无法在 Inno Setup 中使用 [Files] 部分执行此操作。

如果您需要在运行/安装时克隆文件,您所能做的就是将它们安装到临时文件夹,然后使用 Pascal 脚本复制它们。

[Files]
Source: "MyProg.exe"; DestDir: "{tmp}"

[Code]
procedure CurStepChanged(CurStep: TSetupStep);
var
  I: Integer;
  SourcePath: string;
  TargetPath: string;
begin
  if CurStep = ssPostInstall then
  begin
    for I := 0 to NumberOfCustomers - 1 then
    begin
      SourcePath := ExpandConstant('{tmp}\MyProg.exe');
      TargetPath := GetPathForCustomer(I) + '\MyProg.exe';
      if FileCopy(SourcePath, TargetPath, False) then
      begin
        Log(Format('Installed for customer %d', [I]));
      end
        else
      begin
        Log(Format('Failed to install for customer %d', [I]));
      end;
    end;
  end;
end;

(您必须将 NumberOfCustomersGetPathForCustomer 替换为您的实现)

尽管如此,您将不会获得任何进度条,并且会丢失 Inno Setup 的所有内置错误处理功能。您还必须在 Pascal Script 中实现卸载。

<小时/>

如果您在编译时读取 INI 文件,那肯定会更好。这意味着您必须在每次更改 INI 文件时重新生成安装程序。但这可以通过单击一下命令行编译器来完成。

尽管使用预处理器解析 INI 文件并不容易。

<小时/>

另一个黑客解决方案是在[Files]部分中生成大量相同的条目,然后可以在运行/安装时动态地将其与客户关联。它不是通用的,因为总会有一个上限。但如果你知道你永远不会拥有比例如更多的东西。 100个客户,这是一个可行的选择。进度条、错误处理和卸载都将起作用。

<小时/>

我不明白,[Languages] 部分与 INI 文件有什么关系,所以我跳过它。

<小时/>

旁注:您的 GetCustomersFromFileGetCustomersFromFile 可以使用 GetIniString 替换为几行代码和TStringList.CommaText。但这是一个单独的问题。

关于arrays - 创新设置: Single installer that reads names from an INI file and creates an installation for each name,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57944160/

相关文章:

javascript - 如何在 Three.js 中加载 json 对象数组?

javascript - 数组索引在 $.get 中不起作用

arrays - 如果元素已经存在,如何避免添加到数组

version - 在 Inno Setup 中比较版本字符串

c# - 你知道我可以在 C# 中使用的 Inno Setup 包装器吗?

delphi - 无法从 PascalScript 调用 Get_ProcAddress

inno-setup - 在 Inno Setup 中使用字体大小缩放单选按钮列表

inno-setup - Inno 安装程序 : How to display license page before custom page shows from procedure InitializeWizard();

python - numpy 中的索引(与 max/argmax 相关)

windows - 防止已安装的应用程序在静默安装期间启动