views:

932

answers:

6

Want to obtain Delphi Application build # and post into title bar

A: 

Check this URL

link text

vIceBerg
Good link, but lousy answer. Please summarize the contents of the link: What kind of solution should we expect to find by following the link, and what are the important functions to pay attention to?
Rob Kennedy
+4  A: 

Pass the full file name of your EXE to this function, and it will return a string like: 2.1.5.9, or whatever your version # is.

function GetFileVersion(exeName : string): string;
const
  c_StringInfo = 'StringFileInfo\040904E4\FileVersion';
var
  n, Len : cardinal;
  Buf, Value : PChar;
begin
  Result := '';
  n := GetFileVersionInfoSize(PChar(exeName),n);
  if n > 0 then begin
    Buf := AllocMem(n);
    try
      GetFileVersionInfo(PChar(exeName),0,n,Buf);
      if VerQueryValue(Buf,PChar(c_StringInfo),Pointer(Value),Len) then begin
        Result := Trim(Value);
      end;
    finally
      FreeMem(Buf,n);
    end;
  end;
end;

After defining that, you can use it to set your form's caption like so:

procedure TForm1.FormShow(Sender: TObject);
begin 
  //ParamStr(0) is the full path and file name of the current application
  Form1.Caption := Form1.Caption + ' version ' + GetFileVersion(ParamStr(0));
end;
JosephStyons
Joseph, you should protect your AllocMem with a try...finally
François
Right you are- done.
JosephStyons
Joseph, your version doesn't work under Delphi 2007.
Wodzu
@Wodzu: it works for me in D2007. Does your project have the "Include version information in project" option checked under Project->Options->Version Info? What does Windows Explorer tell you the file version is?
JosephStyons
+4  A: 

Here is how I do it. I put this in almost all of my small utilities:

procedure GetBuildInfo(var V1, V2, V3, V4: word);
var
  VerInfoSize, VerValueSize, Dummy: DWORD;
  VerInfo: Pointer;
  VerValue: PVSFixedFileInfo;
begin
  VerInfoSize := GetFileVersionInfoSize(PChar(ParamStr(0)), Dummy);
  if VerInfoSize > 0 then
  begin
      GetMem(VerInfo, VerInfoSize);
      try
        if GetFileVersionInfo(PChar(sFileName), 0, VerInfoSize, VerInfo) then
        begin
          VerQueryValue(VerInfo, '\', Pointer(VerValue), VerValueSize);
          with VerValue^ do
          begin
            V1 := dwFileVersionMS shr 16;
            V2 := dwFileVersionMS and $FFFF;
            V3 := dwFileVersionLS shr 16;
            V4 := dwFileVersionLS and $FFFF;
          end;
        end;
      finally
        FreeMem(VerInfo, VerInfoSize);
      end;
  end;
end;

function GetBuildInfoAsString: string;
var
  V1, V2, V3, V4: word;
begin
  GetBuildInfo(V1, V2, V3, V4);
  Result := IntToStr(V1) + '.' + IntToStr(V2) + '.' +
    IntToStr(V3) + '.' + IntToStr(V4);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Form1.Caption := Form1.Caption + ' - v' + GetBuildInfoAsString;
end;
Mick
This is very nice
JosephStyons
Mick, you should check the returned VerInfoSize like Joseph, and only pursue if > 0, as it may not have file version informastion.
François
A try...finally would not be bad either for the GetMem/FreeMem
François
I just added the try...finally.
Mick
@Francois - done.
Mick
+1  A: 

Here is a wonderful OOP approach to retrieve an application's version information. http://www.delphidabbler.com/articles?article=20

Jim Fritchman
+5  A: 

I most strongly recommend not to use GetFileVersion when you want to know the version of the executable that is currently running! I have two pretty good reasons to do this:

  1. The executable may be unaccessible (disconnected drive/share), or changed (.exe renamed to .bak and replaced by a new .exe without the running process being stopped).
  2. The version data you're trying to read has actually already been loaded into memory, and is available to you by loading this resource, which is always better than to perform extra (relatively slow) disk operations.

To load the version resource in Delphi I use code like this:

uses Windows,Classes,SysUtils;
var
  verblock:PVSFIXEDFILEINFO;
  versionMS,versionLS:cardinal;
  verlen:cardinal;
  rs:TResourceStream;
  m:TMemoryStream;
  p:pointer;
  s:cardinal;
begin
  m:=TMemoryStream.Create;
  try
    rs:=TResourceStream.CreateFromID(HInstance,1,RT_VERSION);
    try
      m.CopyFrom(rs,rs.Size);
    finally
      rs.Free;
    end;
    m.Position:=0;
    if VerQueryValue(m.Memory,'\',pointer(verblock),verlen) then
      begin
        VersionMS:=verblock.dwFileVersionMS;
        VersionLS:=verblock.dwFileVersionLS;
        AppVersionString:=Application.Title+' '+
          IntToStr(versionMS shr 16)+'.'+
          IntToStr(versionMS and $FFFF)+'.'+
          IntToStr(VersionLS shr 16)+'.'+
          IntToStr(VersionLS and $FFFF);
      end;
    if VerQueryValue(m.Memory,PChar('\\StringFileInfo\\'+
      IntToHex(GetThreadLocale,4)+IntToHex(GetACP,4)+'\\FileDescription'),p,s) or
        VerQueryValue(m.Memory,'\\StringFileInfo\\040904E4\\FileDescription',p,s) then //en-us
          AppVersionString:=PChar(p)+' '+AppVersionString;
  finally
    m.Free;
  end;
end;
Stijn Sanders
I'll vote this up if you make the code exception-safe with regard to memory and resource allocations.
mghie
I've added try-finally's, should do the trick. In case you were wondering what the TMemoryStream's for: VerQueryValue had trouble reading from rs.Memory directory...
Stijn Sanders
If resources are anything like they were in my API days, they aren't already in memory, but are fetched from the file. Also, it would be unusual to be doing a swap underneath the app, so I don't think it worth worrying about for most people.
mj2008
There's nothing unusual about renaming a running executable, it's the accepted workaround for Windows' inability to overwrite it. Update routines often rename the running executable to be able to copy the new version to the original location.
mghie
This is an awful lot of code just to extract version info.There should be something simple, like just calling a function (for example get **majorversion**) in the RTTI....
Yogi Yang 007
He wants to post the build # into the title bar. To me, that means the application is looking at it's own version information. So part of your scenario #1 is not valid; the EXE will always have access to itself. It might have been renamed though; that is a good point.
JosephStyons
+1  A: 

We do this for all our apps but we use a Raize component RzVersioninfo. works quite well just need to use the following code

on form create

Caption := RzVersioninfo1.filedescripion + ': ' + RzVersionInfo1.FileVersion;

obviously if you don't want any of the other components from raize use one of the options above as there is a cost to the raize components.

delphigirl