[Lazarus] Program version
Antonio Fortuny
a.fortuny at sitasoftware.lu
Thu Nov 7 15:08:10 CET 2013
Hi again.
I succeeded to make one source unit which when used into any Lazarus
unit, gives the version of any file as far as the file :
- has been compiled whith Lazarus or Delphi
- version information is in the resource data ad hoc (as Lazarus and
Delphi provide)
The file to analyze can be any executable file provided that the
standard OS signatures are at the beginning of the file:
- 'MZ' as the first two chars of the file for any windows program
(inclusive WinCE)
- #127+'ELF' as the first four chars of a Linux executable file
The unit can be compiled by Lazarus (or FPC I guess) on Win32, Win64,
Linux x86_64 (I guess i386 too)
Targets can be Win32, WinCE, Win64, Linux x86_64
A program using the version unit runs on Win32, win64, winCE, Linux x86_64
Whatever the target can be, there is no need to change anything. Same
source runs on all named platforms.
In case of trouble, the unit is supposed not to blow up. It gives a
blank version intead.ยต
See th source unit as attachment.
As I'm not perfect, so I suppose that my code could easily be changed,
adapted or made better in any way. Feel free to comment for improvements
There are not very much comments as code is almost self explanatory but
there improvements can be made as well.
Antonio.
-------------- next part --------------
unit uProgramVersion;
{
Author: Antonio Fortuny (a(DOT)fortuny(AT)sitasoftawre(DOT)lu )
Date: nov/2013
Company: Sita Software
Location: Luxembourg
www.sita.lu
}
interface
uses
Classes,
{$IFNDEF LINUX}
windows,
{$ENDIF}
SysUtils;
type
TVersion = record
Major, Minor, Release, Build: Integer;
end;
PTVersion = ^TVersion;
{$IFDEF WINCE}
function ReadVersionInfo(const sProgram: WideString; Out vv: PTVersion) :Boolean;
function ProgramVersion(const sProgram: WideString) : WideString;
function ProgramVersionOnly(const sProgram: WideString) : WideString;
function ProgramFullVersion(const sProgram: WideString) : WideString;
function AnyProgramVersion(const sProgram: WideString): WideString; overload;
function AnyProgramVersion(const sProgram: string; Out vv: PTVersion) :Boolean; overload;
{$ELSE}
function ReadVersionInfo(const sProgram: string; Out vv: PTVersion) :Boolean;
function ProgramVersion(const sProgram: string) : string;
function ProgramVersionOnly(const sProgram: string) : string;
function ProgramFullVersion(const sProgram: string) : string;
function AnyProgramVersion(const sProgram: string): String; overload;
function AnyProgramVersion(const sProgram: string; Out vv: PTVersion) :Boolean; overload;
{$ENDIF}
function CurrentProgramVersion(const sProgram: string; const ExecType: char='W'): String;
implementation
uses
elfreader,
winpeimagereader,
resource,
versionresource;
{$IFDEF WINCE}
function ReadVersionInfo(const sProgram: WideString; Out vv: PTVersion): Boolean;
{$ELSE}
function ReadVersionInfo(const sProgram: string; Out vv: PTVersion) :Boolean;
{$ENDIF}
begin
if AnyProgramVersion(sProgram, vv) then
Result := True
else begin
Result := False;
vv := New(PTVersion);
vv^.Major := 0;
vv^.Minor := 0;
vv^.Release := 0;
vv^.Build := 0;
end;
end;
{$IFDEF WINCE}
function ProgramVersionOnly(const sProgram: WideString) : WideString;
{$ELSE}
function ProgramVersionOnly(const sProgram: string): string;
{$ENDIF}
var
vver: PTVersion=nil;
begin
try
Result := '0.0.0.0';
if ReadVersionInfo(sProgram, vver) then begin
//VersionProgramme := Format('%d.%d.%d.%d', [vver.Major, vver.Minor, vver.Release, vver.Build]);
Result := Format('%d.%d.%d.%d', [vver^.Major, vver^.Minor, vver^.Release, vver^.Build]);
end;
finally
if Assigned(vver) then
Dispose(vver);
end;
end;
{$IFDEF WINCE}
function ProgramFullVersion(const sProgram: WideString) : WideString;
{$ELSE}
function ProgramFullVersion(const sProgram: string) : string;
{$ENDIF}
var
vver: PTVersion=nil;
begin
// Initialisation de l'application:
try
Result := '000.000.000.000';
if sProgram = EmptyStr then
Exit;
if ReadVersionInfo(sProgram, vver) then begin
//VersionProgramme := Format('%d.%d.%d.%d', [vver.Major, vver.Minor, vver.Release, vver.Build]);
Result := Format('%.3d.%.3d.%.3d.%.3d', [vver^.Major, vver^.Minor, vver^.Release, vver^.Build]);
end;
finally
if Assigned(vver) then
Dispose(vver);
end;
end;
function CurrentProgramVersion(const sProgram: string; const ExecType: char='W'): String;
var
RS : TResources;
E : TWinPEImageResourceReader=nil;
EL : TElfResourceReader=nil;
VR : TVersionResource;
I : Integer;
wProgram: String;
ar: array[0..4] of byte;
begin
{
Msg := CurrentProgramVersion(ParamStr(0));
DoLog(Format('version ce programme %s', [Msg]));
Msg := CurrentProgramVersion('D:\Compiled\Lazarus\i386-win32\ipconsole.exe');
DoLog(Format('version lazarus win32 "D:\Compiled\Lazarus\i386-win32\ipconsole.exe" %s', [Msg]));
Msg := CurrentProgramVersion('D:\Compiled\BackupClient.exe');
DoLog(Format('version Delphi win32 "D:\Compiled\BackupClient.exe" %s', [Msg]));
Msg := CurrentProgramVersion('D:\Compiled\Lazarus\arm-wince\Commandes.exe');
DoLog(Format('version Delphi winCE "D:\Compiled\Lazarus\arm-wince\Commandes.exe" %s', [Msg]));
try
Msg := CurrentProgramVersion('T:\compiled\TestVersionLinux', 'L');
DoLog(Format('version Delphi winCE "T:\compiled\TestVersionLinux" %s', [Msg]));
except
DoLog(Format('version Delphi winCE "T:\compiled\TestVersionLinux" %s', ['Exception']));
end;
}
if sProgram = EmptyStr then
wProgram := ParamStr(0)
else
wProgram := sProgram;
RS:=TResources.Create;
try
try
if ExecType = 'W' then begin
E := TWinPEImageResourceReader.Create;
Rs.LoadFromFile(wProgram, E);
end else begin
EL := TElfResourceReader.Create;
Rs.LoadFromFile(wProgram, EL);
end;
finally
if Assigned(E) then
E.Free;
if Assigned(EL) then
EL.Free;
end;
VR:=Nil;
I:=0;
While (VR=Nil) and (I < RS.Count) do begin
if RS.Items[i] is TVersionResource then
VR := TVersionResource(RS.Items[i]);
Inc(I);
end;
if VR <> Nil then begin
Result := Format('%d.%d.%d.%d',[VR.FixedInfo.FileVersion[0], VR.FixedInfo.FileVersion[1], VR.FixedInfo.FileVersion[2], VR.FixedInfo.FileVersion[3]]);
End ;
Finally
RS.FRee;
end;
{
try
E:=TWinPEImageResourceReader.Create;
try
Rs.LoadFromFile(wProgram, E);
finally
E.Free;
end;
VR:=Nil;
I:=0;
While (VR=Nil) and (I < RS.Count) do begin
if RS.Items[i] is TVersionResource then
VR:=TVersionResource(RS.Items[i]);
Inc(I);
end;
if VR <> Nil then begin
Result := Format('%d.%d.%d.%d',[VR.FixedInfo.FileVersion[0], VR.FixedInfo.FileVersion[1], VR.FixedInfo.FileVersion[2], VR.FixedInfo.FileVersion[3]]);
End ;
Finally
RS.FRee;
end;
}
end;
{$IFDEF WINCE}
function AnyProgramVersion(const sProgram: WideString): WideString;
{$ELSE}
function AnyProgramVersion(const sProgram: string): String;
{$ENDIF}
var
vv: PTVersion;
begin
if AnyProgramVersion(sProgram, vv) then begin
Result := Format('%d.%d.%d.%d', [vv^.Major, vv^.Minor, vv^.Release, vv^.Build]);
Dispose(vv);
end
else
Result := '0.0.0.0';
end;
{$IFDEF WINCE}
function AnyProgramVersion(const sProgram: string; Out vv: PTVersion) :Boolean;
{$ELSE}
function AnyProgramVersion(const sProgram: string; Out vv: PTVersion) :Boolean;
{$ENDIF}
const
WIN_EXE: String = 'MZ';
LINUX_EXE: String = #127 + 'ELF';
var
wFileStr: TFileStream;
RS : TResources;
E : TWinPEImageResourceReader=nil;
EL : TElfResourceReader=nil;
VR : TVersionResource;
I : Integer;
{$IFDEF WINCE}
wProgram: WideString;
{$ELSE}
wProgram: String;
{$ENDIF}
ar: array[0..4] of byte;
ExecType: char;
begin
Result := False;
vv := New(PTVersion);
with vv^ do begin
Major:= -1;
Minor := 0;
Release := 0;
Build := 0;
end;
if sProgram = EmptyStr then
wProgram := ParamStr(0)
else
wProgram := sProgram;
if not FileExists(wProgram) then begin
// program name without path, assume directory of executing program
if Pos(DirectorySeparator, wProgram) = 0 then begin
wProgram := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + sProgram;
if not FileExists(wProgram) then
Exit;
end else
// no path delimiter, get out
Exit;
end else
wProgram := sProgram;
wFileStr := TFileStream.Create(sProgram, fmOpenRead);
try
// check what kind of executable an get resources accordingly
wFileStr.Read(ar, 4);
Finally
wFileStr.Free;
end;
if CompareMem(@(ar), Pchar(WIN_EXE), 2) then
ExecType := 'W'
else
if CompareMem(@(ar), Pchar(LINUX_EXE), 4) then
ExecType := 'L'
else
Exit;
RS:=TResources.Create;
try
try
if ExecType = 'W' then begin
E := TWinPEImageResourceReader.Create;
Rs.LoadFromFile(wProgram, E);
end else begin
EL := TElfResourceReader.Create;
Rs.LoadFromFile(wProgram, EL);
end;
finally
if Assigned(E) then
E.Free;
if Assigned(EL) then
EL.Free;
end;
VR:=Nil;
I:=0;
While (VR=Nil) and (I < RS.Count) do begin
if RS.Items[i] is TVersionResource then
VR := TVersionResource(RS.Items[i]);
Inc(I);
end;
if VR <> Nil then begin
with vv^ do begin
Major:= VR.FixedInfo.FileVersion[0];
Minor := VR.FixedInfo.FileVersion[1];
Release := VR.FixedInfo.FileVersion[2];
Build := VR.FixedInfo.FileVersion[3];
end;
Result := True
End ;
Finally
RS.FRee;
end;
end;
{$IFDEF WINCE}
function ProgramVersion(const sProgram: WideString): WideString;
{$ELSE}
function ProgramVersion(const sProgram: string) : string;
{$ENDIF}
begin
// Initialisation de l'application:
Result := ExtractFileName(sProgram) + ' v.' + ProgramVersionOnly(sProgram);
end;
end.
More information about the Lazarus
mailing list