5

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.

Community
  • 1
  • 1

2 Answers2

14

There's no CompareVersion function in Inno Setup (there is one in the current 6.1 beta, 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 beta supports version comparing nativally with its ComparePackedVersion function (use GetPackedVersion to obtain binary version in the required form).


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.

Martin Prikryl
  • 167,268
  • 50
  • 405
  • 846
  • you have helped me a lot, thank you! it works perfectly – Williams Mogollon Jun 15 '16 at 21:57
  • 2
    +1. I moved version number extracting to `function NextIntFromVersion(var S: string): Integer;` and then in `CompareVersion` in while loop I just have `Result := NextIntFromVersion(V1) - NextIntFromVersion(V2);`. It changes return values a little: for `V1` older than `V2` you just get negative number, for `V1` newer than `V2` - positive. Other than that it works the same and is a bit shorter. :) – Tithen-Firion Mar 23 '18 at 16:40
  • 1
    If anyone needs it, you can avoid exceptions and assume `0` if you replace each `StrToInt` with `StrToIntDef` (use `0` as the 2nd parameter). – Bill_Stewart Dec 10 '19 at 21:15
2

I came up with this solution that is a bit shorter by using recursion. I wrote it as a procedure in order to return the result from the recursion correctly. Maybe my parameter usage isn't perfect, but it works.

procedure VerStrCompare(S1,S2:String; var pComp:Integer);
var nE1,nE2,nV1,nV2:Integer;

begin
 if (Length(S1)>0) OR (Length(S2)>0) then begin
  nE1:=Pos('.',S1+'.');
  nE2:=Pos('.',S2+'.');
  if nE1>1 then nV1:=StrToInt(Copy(s1,1,(nE1-1))) else nV1:=0;
  if nE2>1 then nV2:=StrToInt(Copy(s2,1,(nE2-1))) else nV2:=0;
  if nV1=nV2 then VerStrCompare(Copy(s1,nE1+1,Length(s1)),Copy(s2,nE2+1,Length(s2)),pComp)
   else if nV1>nV2 then pComp:=1
   else if nV1<nV2 then pComp:=-1;
  end 
  else pComp:=0;
end;

Usage: VerStrCompare(String1,String2,Result)
where Result=0 if both strings are the same dotted decimal versions.
Result=1 if String1 is newer (higher version) than String2
Result=-1 if String1 is older (lower version) than String2

Martin Prikryl
  • 167,268
  • 50
  • 405
  • 846
Thomas F
  • 21
  • 2