Compare version strings in Inno Setup

inno-setup, pascalscript, version

Solution

There's no `CompareVersion` function in Inno Setup (there is one since 6.1, see below).

You need to define your own.

Something like:

function CompareVersion(V1, V2: string): Integer;
var
  P, N1, N2: Integer;
begin
  Result := 0;
  while (Result = 0) and ((V1 <> '') or (V2 <> '')) do
  begin
    P := Pos('.', V1);
    if P > 0 then
    begin
      N1 := StrToInt(Copy(V1, 1, P - 1));
      Delete(V1, 1, P);
    end
      else
    if V1 <> '' then
    begin
      N1 := StrToInt(V1);
      V1 := '';
    end
      else
    begin
      N1 := 0;
    end;
  
    P := Pos('.', V2);
    if P > 0 then
    begin
      N2 := StrToInt(Copy(V2, 1, P - 1));
      Delete(V2, 1, P);
    end
      else
    if V2 <> '' then
    begin
      N2 := StrToInt(V2);
      V2 := '';
    end
      else
    begin
      N2 := 0;
    end;

    if N1 < N2 then Result := -1
      else
    if N1 > N2 then Result := 1;
  end;
end;

- Returns `0`, if the versions are equal.

- Returns `-1`, if the `V1` is older than the `V2`.

- Returns `1`, if the `V1` is newer than the `V2`.

- `1.12` is considered newer than `1.1`.

- `1.1` is considered the same as `1.1.0`.

- Throws an exception, when a version is syntactically invalid (only digits and dots are allowed).

Inno Setup 6.1 and newer supports version comparing natively with its `ComparePackedVersion` function.

Use `GetPackedVersion` to obtain binary version in the required form. And `PackVersionComponents` or `StrToVersion` to calculate the packed version for a specific (hardcoded) version for the comparison.

Unit tests:

procedure CompareVersionTest(V1, V2: string; Expected: Integer);
var
  R: Integer;
  M: string;
begin
  M := Format('Comparing [%s] vs. [%s] - expecting %d - ', [V1, V2, Expected]);
  R := CompareVersion(V1, V2);
  if R <> Expected then
  begin
    RaiseException(M + Format('Failed - Got %d', [R]));
  end
    else
  begin
    Log(M + 'Passed');
  end;
end;

procedure CompareVersionTests;
begin
  CompareVersionTest('1', '1', 0);
  CompareVersionTest('1.2', '1.2', 0);
  CompareVersionTest('1.2.3', '1.2.3', 0);
  CompareVersionTest('1', '2', -1);
  CompareVersionTest('1', '3', -1);
  CompareVersionTest('2', '3', -1);
  CompareVersionTest('2', '1', 1);
  CompareVersionTest('3', '1', 1);
  CompareVersionTest('3', '2', 1);
  CompareVersionTest('1', '12', -1);
  CompareVersionTest('12', '2', 1);
  CompareVersionTest('12', '12', 0);
  CompareVersionTest('1.2', '1.3', -1);
  CompareVersionTest('1.3', '1.2', 1);
  CompareVersionTest('1.2', '11.2', -1);
  CompareVersionTest('11.2', '1.2', 1);
  CompareVersionTest('1.1', '1.12', -1);
  CompareVersionTest('1.11', '1.12', -1);
  CompareVersionTest('1.12', '1.1', 1);
  CompareVersionTest('1.12', '1.11', 1);
  CompareVersionTest('1', '1.0', 0);
  CompareVersionTest('1.0', '1', 0);
  CompareVersionTest('1', '1.1', -1);
  CompareVersionTest('1.1', '1', 1);
  CompareVersionTest('1.12.123', '1.12.124', -1);
  CompareVersionTest('1.12.124', '1.12.123', 1);
  CompareVersionTest('1.12.123', '1.13.1', -1);
  CompareVersionTest('1.13.1', '1.12.123', 1);
  CompareVersionTest('1.12.123', '1.13', -1);
  CompareVersionTest('1.13', '1.12.123', 1);
  CompareVersionTest('1.12', '1.13.1', -1);
  CompareVersionTest('1.13.1', '1.12', 1);
end;

If you want to run the unit tests, just call `CompareVersionTests` in `InitializeSetup`.

Problem

I'm reading the value of an INF file, now I need to compare it with the installer version, but when I compile I get an error: Unknown identifier: CompareVersion What is wrong? ``` [Code] function GetKeyValue(const AKeyName, AFileName, ADefault: string): string; var I: Integer; KeyPos: Integer; KeyFull: string; FileLines: TArrayOfString; begin Result := ADefault; if LoadStringsFromFile(AFileName, FileLines) then begin KeyFull := AKeyName + '='; for I := 0 to GetArrayLength(FileLines) - 1 do begin FileLines[I] := TrimLeft(FileLines[I]); KeyPos := Pos(KeyFull, FileLines[I]); if KeyPos > 0 then begin Result := Copy(FileLines[I], KeyPos + Length(AKeyName) + 1, MaxInt); Break; end; end; end; end; var L2Ver2: TLabel; procedure DirEditChange(Sender: TObject); var FilePath: string; begin FilePath := AddBackslash(WizardForm.DirEdit.Text) + 'left4dead2\steam.inf'; L2Ver2.Caption := GetKeyValue('PatchVersion', FilePath, 'N/A'); if (CompareVersion( L2Ver2.Caption, '{#MyAppOldVersion}') = 0) then begin ... end end; ``` I have the error in this line: ``` if (CompareVersion( L2Ver2.Caption, '{#MyAppOldVersion}') = 0) then ``` `{#MyAppOldVersion}` is already defined. This post is related to my previous question: Read an INF file during the Setup. If anyone can help, I would appreciate.

Original source