Recent

Author Topic: Getting Program Version Information (Windows 7 32bit)  (Read 478 times)

Wilko500

  • New Member
  • *
  • Posts: 13
Getting Program Version Information (Windows 7 32bit)
« on: November 23, 2020, 07:31:17 pm »
I've spent a whole afternoon searching for and trying out posted examples and suggestions to no avail.  Coming to Lazarus from VB I'm genuinely surprised that this apparently simple task is evidently not simple. Project-Options allows for enabling version control but no simple way of retrieving it.  Now, that could be because of my inexperience but every one of my attempts fails at the same place. Some of the  posted code examples state that they work so I wonder if it is my Windows setup.
Code: Pascal  [Select][+][-]
  1. procedure TVersionInfo.Load(Instance: THandle);
  2. var
  3.   Stream: TResourceStream;
  4. begin
  5. [color=red]Stream := TResourceStream.CreateFromID(Instance, 1, PChar(RT_VERSION))[/color];
  6.   try
  7.     FVersResource.SetCustomRawDataStream(Stream);
  8.     // access some property to load from the stream
  9.     FVersResource.FixedInfo;
  10.     // clear the stream
  11.     FVersResource.SetCustomRawDataStream(nil);
  12.   finally
  13.     Stream.Free;
  14.   end;
  15. end;
  16.  

and the error (was supposed to be red)

Project xxxx raised exception class 'EResNotFound' with message Resource "1" not found

None of the posted examples mention anything about "resources" I would be very grateful for some pointers to resolve the error our maybe a  working sample.

Thanks
Richard

lucamar

  • Hero Member
  • *****
  • Posts: 3432
Re: Getting Program Version Information (Windows 7 32bit)
« Reply #1 on: November 23, 2020, 09:23:26 pm »
This what we normally use for our "About" boxes:

Code: Pascal  [Select][+][-]
  1. type
  2.  
  3.   TAboutBox = class(TForm)
  4.     { labels, buttons etc. }
  5.   private
  6.     function GetVersionedName: String;
  7.     procedure SetVersionedName(AValue: String);
  8.     function GetDescription: String;
  9.     procedure SetDescription(AValue: String);
  10.     function GetCopyright: String;
  11.     procedure SetCopyright(AValue: String);
  12.   public
  13.     {...}
  14.     procedure LoadFromResource;
  15.     {...}
  16.     property VersionedName: String read GetVersionedName write SetVersionedName;
  17.     property Description: String read GetDescription write SetDescription;
  18.     property Copyright: String read GetCopyright write SetCopyright;
  19.   end;
  20.  
  21. {...}
  22.  
  23. implementation
  24.  
  25. use fileinfo;
  26.  
  27. {
  28.   Property getters and setters simply
  29.   read/write some label captions and
  30.   adjust the dialog bounds ...
  31. }
  32.  
  33. procedure TAboutBox.LoadFromResource;
  34. var
  35.   VerInfo: TFileVersionInfo;
  36. begin
  37.   VerInfo := TFileVersionInfo.Create(Self);
  38.   try
  39.     VerInfo.ReadFileInfo;
  40.     with VerInfo.VersionStrings do begin
  41.       { Unscape() is a function than converts "printf" style
  42.         scaped strings to Pascal strings and allows us to have, e.g.
  43.         FileDescription = 'A "hello world" example app\nNice, aint it?'}
  44.       VersionedName := Unscape(Values['InternalName']
  45.                                + ' '
  46.                                + Values['FileVersion']);
  47.       Description := Unscape(Values['FileDescription']);
  48.       Copyright := Unscape(Values['LegalCopyright']);
  49.     end;
  50.   finally
  51.     VerInfo.Free;
  52.   end;
  53.   Update;
  54. end;
  55.  
  56. {...}
  57.  
  58. end.

Note the important parts, which are those dealing with creating a TFileVersionInfo object, calling its ReadFileInfo and then accessing its VersionStrings.Values([]).

IIRC, we got most of this info from the wiki; let me see if I can find where it is .. Found it: basic methods of getting that information can be seen in the page Show Application Title, Version, and Company

HTH!
« Last Edit: November 23, 2020, 09:26:37 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.10/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Wilko500

  • New Member
  • *
  • Posts: 13
Re: Getting Program Version Information (Windows 7 32bit)
« Reply #2 on: November 26, 2020, 12:15:51 am »
Thanks for your reply and the code example.  I'll try this out at the weekend. 

AL

  • Full Member
  • ***
  • Posts: 211
Re: Getting Program Version Information (Windows 7 32bit)
« Reply #3 on: November 26, 2020, 12:29:56 am »
Here is a unit that does that.

https://sourceforge.net/p/lazarus-ccr/svn/5647/tree/components/lazautoupdate/latest_stable/versionsupport.pas

Seems I have a slightly modified unit with same name.  I do not remember where I got it.

Edit: Found it @: https://forum.lazarus.freepascal.org/index.php/topic,13957.15.html

I added a few funtions to suit my needs.

Code: Pascal  [Select][+][-]
  1. Unit VersionSupport;
  2.  
  3. {$mode objfpc}{$H+}
  4. Interface
  5.  
  6. (*
  7.   Building on the excellent vinfo.pas supplied by Paul Ishenin and available elsewhere on the Lazarus
  8.   Forums
  9.     - I hid the TVersionInfo class from the end user to simplify their (mine) number of required Uses...
  10.     - Added defensive code to TVersionInfo if no build info is compiled into the exe
  11.     - Deduced GetResourceStrings - works under Linux 64/GTK2 with Lazarus 0.9.30, but fails under
  12.       Win XP 32bit/Lazarus 0.9.29 - suspecting my install as the lazresexplorer example also fails
  13.       for me under Lazarus 0.9.29, but works with Lazarus 0.9.30
  14.  
  15.   Trawled through IDE source code, FPC source code and Lazarus supplied example program lasresexplorer
  16.   to find the other defines and lookups...
  17.  
  18.   End user only needs to use VersionSupport - no other units necessary for their project.
  19.  
  20.   Jedi CodeFormatter seems to fail on the {$I %VARIABLE%} references, so sticking them all in here
  21.   means end user code can be neatly formatted using Jedi CodeFormatter
  22.  
  23.   Other interesting includes I picked up in my travels are...
  24.   //  {$I %HOME%} = User Home Directory
  25.   //  {$I %FILE%} = Current pas file
  26.   //  {$I %LINE%} = current line number
  27.  
  28.   Mike Thompson - mike.cornflake@gmail.com
  29.   Origin: July 24 2011
  30.  
  31.   Changes:
  32.   January 2017:   Updated code to cope with refactored LCL Platform Definitions
  33. *)
  34.  
  35. Uses
  36.   Classes, SysUtils ;
  37.  
  38. // Surfacing general defines and lookups
  39. Function GetCompiledDate: String;
  40. Function GetCompilerInfo: String;
  41. Function GetTargetInfo: String;
  42. Function GetOS: String;
  43. Function GetCPU: String;
  44. Function GetLCLVersion: String;
  45. Function GetWidgetSet: String;
  46.  
  47. // Exposing resource and version info compiled into exe
  48. Function GetResourceStrings(oStringList : TStringList) : Boolean;
  49. Function GetFileVersion: String;
  50. Function GetShortFileVersion: String ;
  51. Function GetProductVersion: String;
  52. Function GetFileVersionMajor : Word;
  53.  
  54. Implementation
  55.  
  56. Uses
  57.   resource, versiontypes, versionresource, LCLVersion, InterfaceBase, LCLPlatformDef;
  58.  
  59. Function GetWidgetSet: String;
  60. Begin
  61.   Result := LCLPlatformDisplayNames[WidgetSet.LCLPlatform];
  62. End;
  63.  
  64. Function GetCompilerInfo: String;
  65. begin
  66.   Result := 'FPC '+{$I %FPCVERSION%};
  67. end;
  68.  
  69. Function GetTargetInfo: String;
  70. Begin
  71.   Result := {$I %FPCTARGETCPU%}+' - '+{$I %FPCTARGETOS%};
  72. End;
  73.  
  74. Function GetOS: String;
  75. Begin
  76.   Result := {$I %FPCTARGETOS%};
  77. End;
  78.  
  79. function GetCPU: String;
  80. begin
  81.   Result := {$I %FPCTARGETCPU%};
  82. end;
  83.  
  84. Function GetLCLVersion: String;
  85. Begin
  86.   Result := 'LCL '+lcl_version;
  87. End;
  88.  
  89. Function GetCompiledDate: String;
  90. Var
  91.   sDate, sTime: String;
  92. Begin
  93.   sDate := {$I %DATE%};
  94.   sTime := {$I %TIME%};
  95.  
  96.   Result := sDate + ' at ' + sTime;
  97. End;
  98.  
  99. { Routines to expose TVersionInfo data }
  100.  
  101. Type
  102.   TVersionInfo = Class
  103.   private
  104.     FBuildInfoAvailable: Boolean;
  105.     FVersResource: TVersionResource;
  106.     Function GetFixedInfo: TVersionFixedInfo;
  107.     Function GetStringFileInfo: TVersionStringFileInfo;
  108.     Function GetVarFileInfo: TVersionVarFileInfo;
  109.   public
  110.     Constructor Create;
  111.     Destructor Destroy; override;
  112.  
  113.     Procedure Load(Instance: THandle);
  114.  
  115.     Property BuildInfoAvailable: Boolean Read FBuildInfoAvailable;
  116.  
  117.     Property FixedInfo: TVersionFixedInfo Read GetFixedInfo;
  118.     Property StringFileInfo: TVersionStringFileInfo Read GetStringFileInfo;
  119.     Property VarFileInfo: TVersionVarFileInfo Read GetVarFileInfo;
  120.   End;
  121.  
  122. Var
  123.   FInfo: TVersionInfo;
  124.  
  125. Procedure CreateInfo;
  126. Begin
  127.   If Not Assigned(FInfo) Then
  128.   Begin
  129.     FInfo := TVersionInfo.Create;
  130.     FInfo.Load(HINSTANCE);
  131.   End;
  132. End;
  133.  
  134. Function GetResourceStrings(oStringList: TStringList): Boolean;
  135. Var
  136.   i, j : Int32;
  137.   oTable : TVersionStringTable;
  138. begin
  139.   CreateInfo;
  140.  
  141.   oStringList.Clear;
  142.   Result := False;
  143.  
  144.   If FInfo.BuildInfoAvailable Then
  145.   Begin
  146.     Result := True;
  147.     For i := 0 To FInfo.StringFileInfo.Count-1 Do
  148.     Begin
  149.       oTable := FInfo.StringFileInfo.Items[i];
  150.  
  151.       For j := 0 To oTable.Count-1 Do
  152.         If Trim(oTable.ValuesByIndex[j])<>'' Then
  153.           oStringList.Values[oTable.Keys[j]] := oTable.ValuesByIndex[j];
  154.     end;
  155.   end;
  156. end;
  157. Function ProductShortVersionToString(PV: TFileProductVersion): String;
  158. Begin
  159.   Result := Format('%d.%d', [PV[0], PV[1]]);
  160. End;
  161.  
  162. Function ProductVersionToString(PV: TFileProductVersion): String;
  163. Begin
  164.   Result := Format('%d.%d.%d.%d', [PV[0], PV[1], PV[2], PV[3]]);
  165. End;
  166. Function ProductVersionMajor(PV: TFileProductVersion): Word;
  167. Begin
  168.   Result := PV[0] ;
  169. End;
  170.  
  171. Function GetFileVersionMajor: Word ;
  172. Begin
  173.   CreateInfo;
  174.  
  175.   If FInfo.BuildInfoAvailable Then
  176.   begin
  177.     Result := ProductVersionMajor(FInfo.FixedInfo.FileVersion)  ;   //Product Version
  178.   End
  179.   Else
  180.     Result := 0;
  181. End;
  182. Function GetProductVersion: String;
  183. Begin
  184.   CreateInfo;
  185.  
  186.   If FInfo.BuildInfoAvailable Then
  187.     Result := ProductVersionToString(FInfo.FixedInfo.ProductVersion)
  188.   Else
  189.     Result := 'No build information available';
  190. End;
  191. Function GetShortFileVersion: String;
  192. Begin
  193.   CreateInfo;
  194.  
  195.   If FInfo.BuildInfoAvailable Then
  196.     Result := ProductShortVersionToString(FInfo.FixedInfo.FileVersion)
  197.   Else
  198.     Result := 'No build information available';
  199. End;
  200.  
  201. Function GetFileVersion: String;
  202. Begin
  203.   CreateInfo;
  204.  
  205.   If FInfo.BuildInfoAvailable Then
  206.     Result := ProductVersionToString(FInfo.FixedInfo.FileVersion)
  207.   Else
  208.     Result := 'No build information available';
  209. End;
  210.  
  211. { TVersionInfo }
  212.  
  213. Function TVersionInfo.GetFixedInfo: TVersionFixedInfo;
  214. Begin
  215.   Result := FVersResource.FixedInfo;
  216. End;
  217.  
  218. Function TVersionInfo.GetStringFileInfo: TVersionStringFileInfo;
  219. Begin
  220.   Result := FVersResource.StringFileInfo;
  221. End;
  222.  
  223. Function TVersionInfo.GetVarFileInfo: TVersionVarFileInfo;
  224. Begin
  225.   Result := FVersResource.VarFileInfo;
  226. End;
  227.  
  228. Constructor TVersionInfo.Create;
  229. Begin
  230.   Inherited Create;
  231.  
  232.   FVersResource := TVersionResource.Create;
  233.   FBuildInfoAvailable := False;
  234. End;
  235.  
  236. Destructor TVersionInfo.Destroy;
  237. Begin
  238.   FVersResource.Free;
  239.  
  240.   Inherited Destroy;
  241. End;
  242.  
  243. Procedure TVersionInfo.Load(Instance: THandle);
  244. Var
  245.   Stream: TResourceStream;
  246.   ResID: Int32;
  247.   Res: TFPResourceHandle;
  248. Begin
  249.   FBuildInfoAvailable := False;
  250.   ResID := 1;
  251.  
  252.   // Defensive code to prevent failure if no resource available...
  253.   Res := FindResource(Instance, PChar(PtrInt(ResID)), PChar(RT_VERSION));
  254.   If Res = 0 Then
  255.     Exit;
  256.  
  257.   Stream := TResourceStream.CreateFromID(Instance, ResID, PChar(RT_VERSION));
  258.   Try
  259.     FVersResource.SetCustomRawDataStream(Stream);
  260.  
  261.     // access some property to load from the stream
  262.     FVersResource.FixedInfo;
  263.  
  264.     // clear the stream
  265.     FVersResource.SetCustomRawDataStream(nil);
  266.  
  267.     FBuildInfoAvailable := True;
  268.   Finally
  269.     Stream.Free;
  270.   End;
  271. End;
  272.  
  273. Initialization
  274.   FInfo := nil;
  275.  
  276. Finalization
  277.   If Assigned(FInfo) Then
  278.     FInfo.Free;
  279. End.
  280.  
  281.  
  282.  
« Last Edit: November 26, 2020, 12:51:40 am by AL »
Laz 2.1.0, fpc 3.3.1, Win10
Laz 2.1.0, fpc 3.3.1, Mac OS Mojave running on VMWare
Laz 2.1.0  fpc 3.3.1 Ubuntu 20.04

Wilko500

  • New Member
  • *
  • Posts: 13
Solved - Getting Program Version Information (Windows 7 32bit)
« Reply #4 on: December 06, 2020, 11:19:01 pm »
Thanks to Al & Lucama for both hints and sample code. Took a bit longer than I expected to get back to.   Very much appreciated. I used TFileVersionInfo and for now just a simple function to return FileVersion so problem solved, now working.

 

TinyPortal © 2005-2018