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.