Search code examples
versioninno-setuppascalscript

Compare version strings in Inno Setup


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.


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.