English 中文(简体)
How to determine Delphi Application Version
原标题:

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

问题回答

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(ParamStr(0)), 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;

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;

Thanks to the posts above, I made my own library for this purpose.

I believe that it is a little bit more correct than all other solutions here, so I share it - feel free to reuse it...

unit KkVersion;

interface

function FileDescription: String;
function LegalCopyright: String;
function DateOfRelease: String; // Proprietary
function ProductVersion: String;
function FileVersion: String;

implementation

uses
  Winapi.Windows, System.SysUtils, System.Classes, Math;

(*
  function GetHeader(out AHdr: TVSFixedFileInfo): Boolean;

  var
  BFixedFileInfo: PVSFixedFileInfo;
  RM: TMemoryStream;
  RS: TResourceStream;
  BL: Cardinal;

  begin
  Result := False;
  RM := TMemoryStream.Create;
  try
  RS := TResourceStream.CreateFromID(HInstance, 1, RT_VERSION);
  try
  RM.CopyFrom(RS, RS.Size);
  finally
  FreeAndNil(RS);
  end;

  // Extract header
  if not VerQueryValue(RM.Memory,  \ , Pointer(BFixedFileInfo), BL) then
  Exit;

  // Prepare result
  CopyMemory(@AHdr, BFixedFileInfo, Math.Min(sizeof(AHdr), BL));
  Result := True;
  finally
  FreeAndNil(RM);
  end;
  end;
*)

function GetVersionInfo(AIdent: String): String;

type
  TLang = packed record
    Lng, Page: WORD;
  end;

  TLangs = array [0 .. 10000] of TLang;

  PLangs = ^TLangs;

var
  BLngs: PLangs;
  BLngsCnt: Cardinal;
  BLangId: String;
  RM: TMemoryStream;
  RS: TResourceStream;
  BP: PChar;
  BL: Cardinal;
  BId: String;

begin
  // Assume error
  Result :=   ;

  RM := TMemoryStream.Create;
  try
    // Load the version resource into memory
    RS := TResourceStream.CreateFromID(HInstance, 1, RT_VERSION);
    try
      RM.CopyFrom(RS, RS.Size);
    finally
      FreeAndNil(RS);
    end;

    // Extract the translations list
    if not VerQueryValue(RM.Memory,  \VarFileInfo\Translation , Pointer(BLngs), BL) then
      Exit; // Failed to parse the translations table
    BLngsCnt := BL div sizeof(TLang);
    if BLngsCnt <= 0 then
      Exit; // No translations available

    // Use the first translation from the table (in most cases will be OK)
    with BLngs[0] do
      BLangId := IntToHex(Lng, 4) + IntToHex(Page, 4);

    // Extract field by parameter
    BId :=  \StringFileInfo\  + BLangId +  \  + AIdent;
    if not VerQueryValue(RM.Memory, PChar(BId), Pointer(BP), BL) then
      Exit; // No such field

    // Prepare result
    Result := BP;
  finally
    FreeAndNil(RM);
  end;
end;

function FileDescription: String;
begin
  Result := GetVersionInfo( FileDescription );
end;

function LegalCopyright: String;
begin
  Result := GetVersionInfo( LegalCopyright );
end;

function DateOfRelease: String;
begin
  Result := GetVersionInfo( DateOfRelease );
end;

function ProductVersion: String;
begin
  Result := GetVersionInfo( ProductVersion );
end;

function FileVersion: String;
begin
  Result := GetVersionInfo( FileVersion );
end;

end.

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 =  StringFileInfo40904E4FileVersion ;
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;

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.

From http://www.martinstoeckli.ch/delphi/delphi.html#AppVersion

With this function you can get the version of a file, which contains a version resource. This way you can display the version number of your application in an information dialog. To include a version resource to your Delphi application, set the "Versioninfo" in the project options.

My code:

uses unit Winapi.Windows;

function GetModuleVersion(Instance: THandle; out iMajor, iMinor, iRelease, iBuild: Integer): Boolean;
var
    fileInformation: PVSFIXEDFILEINFO;
    verlen: Cardinal;
    rs: TResourceStream;
    m: TMemoryStream;
begin

   result := false;

    m := TMemoryStream.Create;
    try
        try
          rs := TResourceStream.CreateFromID(Instance, 1, RT_VERSION);
          try
              m.CopyFrom(rs, rs.Size);
          finally
              rs.Free;
          end;
        except
          exit;
        end;

        m.Position:=0;
        if not VerQueryValue(m.Memory,   , Pointer(fileInformation), verlen) then
        begin
          iMajor := 0;
          iMinor := 0;
          iRelease := 0;
          iBuild := 0;
          Exit;
        end;

        iMajor := fileInformation.dwFileVersionMS shr 16;
        iMinor := fileInformation.dwFileVersionMS and $FFFF;
        iRelease := fileInformation.dwFileVersionLS shr 16;
        iBuild := fileInformation.dwFileVersionLS and $FFFF;
    finally
        m.Free;
    end;

    Result := True;
end;

Usage:

  if GetModuleVersion(HInstance, iMajor, iMinor, iRelease, iBuild) then
    ProgramVersion := inttostr(iMajor)+ . +inttostr(iMinor)+ . +inttostr(iRelease)+ . +inttostr(iBuild);




相关问题
determining the character set to use

my delphi 2009 app has a basic translation system that uses GNUGetText. i had used some win API calls to prepare the fonts. i thought it was working correctly until recently when someone from Malta ...

Help with strange Delphi 5 IDE problems

Ok, I m going nuts here. For the last (almost) four years, I ve been putting up with some extremely bad behavior from my Delphi 5 IDE. Problems include: Seemingly random errors in coride50.bpl ...

How to write a Remote DataModule to run on a linux server?

i would like to know if there are any solution to do this. Does anyone? The big picture: I want to access data over the web, using my delphi thin clients. But i´would like to keep my server/service ...

How convert string to integer in Oxygene

In Delphi, there is a function StrToInt() that converts a string to an integer value; there is also IntToStr(), which does the reverse. These functions doesn t appear to be part of Oxygene, and I can ...

Quick padding of a string in Delphi

I was trying to speed up a certain routine in an application, and my profiler, AQTime, identified one method in particular as a bottleneck. The method has been with us for years, and is part of a "...

热门标签