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.