Reputation: 4112
I need to read the VersionInfo from a file (exe or dll) using a TSream.
I cannot use the windows API GetFileVersionInfo, because my file is at memory (TMemoryStream) and I don't want to write the file to disk for get this information, I have some performance restrictions.
Someone can help me?
Upvotes: 1
Views: 628
Reputation: 1839
Use the HInstance value of modules already loaded in .EXE
memory space to get the RT_VERSION
resource using TResourceStream.
By example, to get the MainModule hInstace and respective Version:
var module: HMODULE;
version: String;
...
module := GetModuleHandle(nil);
version := FileVersion(base);
If you can't load as a resource from memory like I did below, you can parse the .EXE
using PE HEADERS and find RT_VERSION
resource using a TMemoryStream.
unit Version;
interface
implementation
uses
Winapi.Windows, System.SysUtils, System.Classes, Math;
function FileVersion(Module: HINST = 0): String;
var
verblock:PVSFIXEDFILEINFO;
versionMS,versionLS:cardinal;
verlen:cardinal;
rs:TResourceStream;
m:TMemoryStream;
p:pointer;
s:cardinal;
begin
m:=TMemoryStream.Create;
try
if Module = 0 then
Module := HInstance;
rs:=TResourceStream.CreateFromID(Module,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;
Result:=
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
Result:=PChar(p)+' '+Result;
finally
m.Free;
end;
end;
end.
Upvotes: 0
Reputation: 598031
If the raw file data is in memory, then the Win32 API cannot help you locate the file's version resource. You will have to manually read and interpret the file's PE header to locate the file's resources table and then loop through the table looking for the desired version resource. Once you have located it, you can use the Win32 API VerQueryValue()
function to access some (but not all) of the values inside of the resource. I say some because VerQueryValue()
internally relies on lookups that GetFileVersionInfo()
establishes at runtime. However, accessing the VS_FIXEDFILEINFO
structure, for instance, works fine without calling GetFileVersionInfo()
first.
Upvotes: 3