Reading Version Information from your EXE

Very often, you have to check some information contained in the VERSIONINFO section of your application and most of the examples you can find on the InterWebz are doing it by using this WinAPI routine: GetFileVersionInfo.

It certainly works and can be used to get the VersionInfo from any file you want, much like in Windows Explorer, because the routine takes a FileName as its main parameter and reads it from its header.

But if you need it from inside the running application, why would you go and read the file on disk (or at least ask the OS for it) when you have the information directly available as a resource.

The main difference is that instead of calling GetFileVersionInfo, you have to find, load and lock the resource. Then you can query the value all the same. (Warning: see Arthur’s comment below and read Raymond Chen’s blog post he references)

procedure GetResourceVersionNumbers(out AMajor, AMinor, ARelease, ABuild: Integer);
{ Get the module version information from the embedded resource.
Called upon Initialization }
var
  HResource: TResourceHandle;
  HResData: THandle;
  PRes: Pointer;
  InfoSize: DWORD;
  FileInfo: PVSFixedFileInfo;
  FileInfoSize: DWORD;
begin
  HResource := FindResource(HInstance, MakeIntResource(VS_VERSION_INFO), RT_VERSION);
  if HResource <> 0 then begin
    HResData:=LoadResource(HInstance, HResource);
    if HResData <> 0 then begin
      PRes:=LockResource(HResData);
      if Assigned(PRes) then begin
        InfoSize := SizeofResource(HInstance, HResource);
        if InfoSize = 0 then
          raise Exception.Create('Can''t get version information.');
        // Query the information for the version
        VerQueryValue(PRes, '\', Pointer(FileInfo), FileInfoSize);
        // Now fill in the version information
        AMajor := FileInfo.dwFileVersionMS shr 16;
        AMinor := FileInfo.dwFileVersionMS and $FFFF;
        ARelease := FileInfo.dwFileVersionLS shr 16;
        ABuild := FileInfo.dwFileVersionLS and $FFFF;
      end;
//      UnlockResource(HResData); // unnecessary per MSDN
//      FreeResource(HResData);   // unnecessary per MSDN
    end;
  end
  else
    RaiseLastOSError;
end;

procedure GetFileVersionNumbers(out AMajor, AMinor, ARelease, ABuild: Integer);
{ Get the file version information. Called upon Initialization }
var
  PInfo: Pointer;
  InfoSize: DWORD;
  FileInfo: PVSFixedFileInfo;
  FileInfoSize: DWORD;
  FileName: string;
  Tmp: DWORD;
begin
  FileName := ParamStr(0);
  // Get the size of the FileVersionInformatioin
  InfoSize := GetFileVersionInfoSize(PChar(FileName), Tmp);
  // If InfoSize = 0, then the file may not exist, or
  // it may not have file version information in it.
  if InfoSize = 0 then
    raise Exception.Create('Can''t get file version information for '+ FileName);
  // Allocate memory for the file version information
  GetMem(PInfo, InfoSize);
  try
    // Get the information
    GetFileVersionInfo(PChar(FileName), 0, InfoSize, PInfo);
    // Query the information for the version
    VerQueryValue(PInfo, '\', Pointer(FileInfo), FileInfoSize);
    // Now fill in the version information
    AMajor := FileInfo.dwFileVersionMS shr 16;
    AMinor := FileInfo.dwFileVersionMS and $FFFF;
    ARelease := FileInfo.dwFileVersionLS shr 16;
    ABuild := FileInfo.dwFileVersionLS and $FFFF;
  finally
    FreeMem(PInfo);
  end;
end;

var
  gMajorVersion: Integer = 0;
  gMinorVersion: Integer = 0;
  gRelease: Integer = 0;
  gBuild: Integer = 0;

initialization
  GetResourceVersionNumbers(gMajorVersion, gMinorVersion, gRelease, gBuild);
//  GetFileVersionNumbers(gMajorVersion, gMinorVersion, gRelease, gBuild);
  ShowMessage(Format('major: %d, minor: %d, release: %d, build: %d',
    [gMajorVersion, gMinorVersion, gRelease, gBuild]));
end.
This entry was posted in Delphi, Resources, Windows and tagged , , . Bookmark the permalink.

4 Responses to Reading Version Information from your EXE

  1. Nice, I think in Delphi the code should be:

    var
    Ver : String;
    begin
    Ver := GetVersionNumber;
    end;

    The reason I think this is because Delphi is awesome and everything should be very simple to do in Delphi.

    • François Gaillard says:

      The main reason I’ve seen for getting the version numbers is to test and check for some special behavior/features.
      And even for just displaying the version in an “About” box, you may want to display it differently depending on the circumstances. So, getting the individual values gives more flexibility.
      You can always easily make a GetStringVersion function available publicly and use it as much as you like.

  2. Arthur Pijpers says:

    Hello François,

    This solution doesn’t work in Windows Server 2003, we just found out. It gives access violations in VerQueryValue. See also http://blogs.msdn.com/b/oldnewthing/archive/2006/12/26/1365215.aspx

    Regards, Arthur Pijpers

    • François Gaillard says:

      Thanks for the warning Arthur.
      Never had this problem (but I’m not sure I used it with Win Server 2003).
      I’m guessing it falls into this Ansi/Unicode mismatch pointed out by Raymond Chen in the blog entry you referenced.
      What version of Delphi are you using to compile the app that misbehave in Win Server 2003?
      How does the Version info from the exe appear in a resource editor?

Leave a Reply

Your email address will not be published. Required fields are marked *