Skip to content

Instantly share code, notes, and snippets.

@dkstar88
Created August 1, 2013 08:51
Show Gist options
  • Save dkstar88/6129669 to your computer and use it in GitHub Desktop.
Save dkstar88/6129669 to your computer and use it in GitHub Desktop.
A generic Version structure utilizing operator override feature in Delphi versions. Currently it supports comparison, and not so useful addition and substraction. Now you can do TVersion('1.0.2.3') > TVersion('1.0.2.2') I also put AppVersion, which returns the version of your running application for both Windows and MacOS. So checking where if t…
unit Version;
interface
uses Types;
type
TVersion = record
Major, Minor, Release, Build: Word;
class operator Equal(a: TVersion; b: TVersion) : Boolean;
class operator NotEqual(a: TVersion; b: TVersion) : Boolean;
class operator GreaterThan(a: TVersion; b: TVersion) : Boolean;
class operator GreaterThanOrEqual(a: TVersion; b: TVersion) : Boolean;
class operator LessThan(a: TVersion; b: TVersion) : Boolean;
class operator LessThanOrEqual(a: TVersion; b: TVersion) : Boolean;
class operator Add(a: TVersion; b: TVersion): TVersion;
class operator Subtract(a: TVersion; b: TVersion): TVersion;
class operator Implicit(AString: String): TVersion;
class operator Explicit(AVersion: TVersion): String;
function IsGreater(AComapredTO: TVersion): Boolean;
function FromString(AStringVersion: String): Boolean;
end;
function FormatVersion(AVer: TVersion): String;
function VersionToInt64(AVer: TVersion): Int64;
function Int64ToVerInfo(AValue: Int64): TVersion;
function CompareVersion(Ver1, Ver2: TVersion): Integer;
// String(AppVersion)
function AppVersion: TVersion;
{$IFDEF MSWINDOWS}
function GetFileVersion(const AFileName: string; Splitchar: Char = '.'): string;
{$ENDIF}
implementation
uses
{$IFDEF MSWINDOWS}
Windows,
{$ENDIF}
{$IFDEF MACOS}
Macapi.CoreFoundation,
{$ENDIF}
SysUtils, Classes;
{$IFDEF MSWINDOWS}
function GetFileVersion(const AFileName: string; Splitchar: Char = '.'): string;
var
FileName: string;
InfoSize, Wnd: DWORD;
VerBuf: Pointer;
FI: PVSFixedFileInfo;
VerSize: DWORD;
begin
Result := '0' + Splitchar + '0' + Splitchar + '0' + Splitchar + '0';
// GetFileVersionInfo modifies the filename parameter data while parsing.
// Copy the string const into a local variable to create a writeable copy.
FileName := AFileName;
UniqueString(FileName);
InfoSize := GetFileVersionInfoSize(PChar(FileName), Wnd);
if InfoSize <> 0 then
begin
GetMem(VerBuf, InfoSize);
try
if GetFileVersionInfo(PChar(FileName), Wnd, InfoSize, VerBuf) then
if VerQueryValue(VerBuf, '\', Pointer(FI), VerSize) then
begin
//
Result := Format('%d%s%d%s%d%s%d', [HiWORD(FI.dwFileVersionMS),
Splitchar, loWord(FI.dwFileVersionMS), Splitchar,
HiWORD(FI.dwFileVersionLS), Splitchar, loWord(FI.dwFileVersionLS)]);
end;
finally
FreeMem(VerBuf);
end;
end;
end;
function AppVersion: TVersion;
begin
Result := GetFileVersion(ParamStr(0));
end;
{$ENDIF}
{$IFDEF MACOS}
function AppVersion: String;
var
CFStr: CFStringRef;
Range: CFRange;
begin
CFStr := CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle,
kCFBundleVersionKey);
Range.location := 0;
Range.length := CFStringGetLength(CFStr);
SetLength(Result, Range.length);
CFStringGetCharacters(CFStr, Range, PChar(Result));
end;
{$ENDIF}
function FormatVersion(AVer: TVersion): String;
begin
Result := Format('%d.%d.%d.%d', [AVer.Major, AVer.Minor, AVer.Release, AVer.Build]);
end;
function VersionToInt64(AVer: TVersion): Int64;
begin
Result := (Int64(AVer.Major) shl 48) or (AVer.Minor shl 32) or (AVer.Release shl 16) or AVer.Build;
end;
function Int64ToVerInfo(AValue: Int64): TVersion;
begin
Result.Major := (AValue shr 48) and $FFFF;;
Result.Minor := (AValue shr 32) and $FFFF;
Result.Release := (AValue shr 16) and $FFFF;
Result.Build := AValue and $FFFF;
end;
function CompareVersion(Ver1, Ver2: TVersion): Integer;
var
v1, v2: Int64;
begin
v1 := VersionToInt64(Ver1);
v2 := VersionToInt64(Ver2);
if v1=v2 then
begin
Result := 0;
end else
begin
if v1>v2 then
Result := 1
else
Result := -1;
end;
end;
{ TVersion }
class operator TVersion.Add(a, b: TVersion): TVersion;
begin
Result.Major := A.Major + B.Major;
Result.Minor := A.Minor + B.Minor;
Result.Release := A.Release + B.Release;
Result.Build := A.Build + B.Build;
end;
class operator TVersion.Equal(a, b: TVersion): Boolean;
begin
Result := CompareVersion(A, B) = 0;
end;
class operator TVersion.Explicit(AVersion: TVersion): String;
begin
Result := FormatVersion(AVersion);
end;
function TVersion.FromString(AStringVersion: String): Boolean;
var
list: TStrings;
tmp: TVersion;
begin
list := TStringList.Create;
try
FillChar(tmp, SizeOf(tmp), #0);
list.Delimiter := '.';
list.DelimitedText := AStringVersion;
if list.Count>0 then tmp.Major := StrToInt(list[0]);
if list.Count>1 then tmp.Minor := StrToInt(list[1]);
if list.Count>2 then tmp.Release := StrToInt(list[2]);
if list.Count>3 then tmp.Build := StrToInt(list[3]);
Self := Tmp;
Result := True;
except
Result := False;
end;
end;
class operator TVersion.GreaterThan(a, b: TVersion): Boolean;
begin
Result := CompareVersion(A, B) > 0;
end;
class operator TVersion.GreaterThanOrEqual(a, b: TVersion): Boolean;
begin
Result := CompareVersion(A, B) >= 0;
end;
class operator TVersion.Implicit(AString: String): TVersion;
begin
Result.FromString(AString);
end;
function TVersion.IsGreater(AComapredTO: TVersion): Boolean;
begin
Result := CompareVersion(Self, AComapredTO) > 0;
end;
class operator TVersion.LessThan(a, b: TVersion): Boolean;
begin
Result := CompareVersion(A, B) < 0;
end;
class operator TVersion.LessThanOrEqual(a, b: TVersion): Boolean;
begin
Result := CompareVersion(A, B) <= 0;
end;
class operator TVersion.NotEqual(a, b: TVersion): Boolean;
begin
Result := CompareVersion(A, B) <> 0;
end;
class operator TVersion.Subtract(a, b: TVersion): TVersion;
begin
Result.Major := A.Major - B.Major;
Result.Minor := A.Minor - B.Minor;
Result.Release := A.Release - B.Release;
Result.Build := A.Build - B.Build;
end;
end.
@onion7878
Copy link

function TVersion.FromString(AStringVersion: String): Boolean;
var
  list: TStrings;
  tmp: TVersion;
begin
  list := TStringList.Create;
  try
    FillChar(tmp, SizeOf(tmp), #0);
    list.Delimiter := '.';
    list.DelimitedText := AStringVersion;
    if list.Count>0 then tmp.Major := StrToInt(list[0]);
    if list.Count>1 then tmp.Minor := StrToInt(list[1]);
    if list.Count>2 then tmp.Release := StrToInt(list[2]);
    if list.Count>3 then tmp.Build := StrToInt(list[3]);
    Self := Tmp;
    Result := True;
  except
    Result := False;
  end;
  list.Free
end;

list is not free

@onion7878
Copy link

function VersionToInt64(AVer: TVersion): UInt64;
begin
  Result := (UInt64(AVer.Major)   shl (16 * 3)) or
            (UInt64(AVer.Minor)   shl (16 * 2)) or
            (UInt64(AVer.Release) shl (16 * 1)) or
            (UInt64(AVer.Build)   shl (16 * 0));
end;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment